5次元のカオス

南の島の学生がつらつらと日々を書き連ねます

underscore.jsについて勉強してみた

underscore.jsについて勉強してみた

先日のことですが、とあるゲーム開発会社に訪問しコードレビューしてもらいました.

その際に、「ここunderscore.jsとか使うともっとスッキリ書けるよ!」という指摘を多数受け、これは勉強してみるかーということでドットインストールを利用して勉強してみました.

すごく便利なライブラリなので使いこなしていけるといいなあ...

以下、自分への健忘録としてメモ.

※ 基本的にドットインストールのまとめです.

underscore.jsとは?

公式サイトより
Underscore is a JavaScript library that provides a whole mess of useful functional 
programming helpers without extending any built-in objects.

英語は相変わらずよく分からないのですが、jsの配列やオブジェクトを簡単に扱うことが出来るようになる便利なライブラリという解釈で良さそうです.

(ホントか?)

DocumentCloud Inc.よりオープンソースとして提供されています.

公式サイトより、underscore.jsかunderscore-min.jsを用意します.

記事を書いた時の情報
underscore.js
Development Version (1.6.0) 44kb, Uncompressed with Plentiful Comments
Production Version (1.6.0)  5.0kb, Minified and Gzipped  (Source Map)

配列の要素をシャッフルする

shuffle

/*下の2つは同じ実行結果*/
/* リファレンスは上の書き方 */
var x = _.shuffle([1, 2, 3, 4, 5, 6]);
var y = _([1, 2, 3, 4, 5, 6]).shuffle();           
console.log(x);

=> [4, 1, 6, 3, 5, 2]

引数として与えた配列をシャッフルし、コピーした配列を返り値としている.

Fisher-Yates shuffleというアルゴリズムが内部で使用されている.

配列の要素をそれぞれ操作する

each

var x = _.each([2, 5, 8], function(value, index, list){
    console.log(num * 2);
});

=> 4, 10, 16が表示される

_.each({one: 1, two: 2, three: 3}, function(value, index, list){
    console.log(value * 2);
});

=> 2, 4, 6が表示される

functionの引数は省略可能(valueだけとかもok).

jsの場合、for inだとオブジェクトに対してkeyを指定しないと値を取り出せないのに対し

_.eachはkeyを省略することができる

for (key in obj) {
  console.log(obj[key]);
}

map

var x = _.map([2, 5, 8], function(value, index, list) {
    return (value * 2);
});

=> [4, 10, 16]

var x = _.map({one: 1, two: 2, three: 3}, function(value, index, list){
    return num * 3;
});

=> { one: 3, two: 6, three: 9 }

functionの引数は省略可能(valueだけとかもok).

var xには新しい配列, オブジェクトが代入される(引数に指定したものはそのまま).

※ each, mapの違いは元々の配列を操作する, 新しく配列を作りなおすという違い

集合に対する操作

find

var array = [2, 5, 8, 42, 12];
var x = _.find(array, function(num) {
    return (num % 2 == 0);
});

=> 2

最初に見つかった要素のみを取り出す

※ 見つからなかった場合、どうなるのか調べる => .find の内部で .anyが呼ばれてるから false?

filter

var array = [2, 5, 8, 42, 12];
var x = _.filter(array, function(num) {
    return (num > 5);
});

=> [8, 42, 12]

条件に一致する値を全てを取り出す

contains

var array = [2, 5, 8, 42, 12];
var x = _.contains(array, 5);

=> true

配列中に指定した値が含まれているかどうか判別する

返り値はtrue/false

集計を行う際のメソッド

groupBy

var array = [1, 2, 5, 8, 42, 12];
var x;
x = _.groupBy(array, function(num) {
    return (num % 3);
});

=> {1: [1], 2: [2, 5, 8]}

var x = _.groupBy(['one', 'two', 'three'], 'length');

=> {3: ["one", "two"], 5: ["three"]}

返り値でグルーピングを行い、それぞれの結果を配列として返す.

countBy

var array = [1, 2, 3, 4, 5];
var x = _.countBy(array, function(num){
    return (num % 2 == 0 ? 'even' : 'odd');
});

=> {odd: 3, even: 2}

その条件に当てはまるものが個数をそれぞれ返す.

sortBy

var array = [1, 2, 3, 4, 5, 6];
var x = _.sortBy(array, function(num) {
    return Math.sin(num);
});

=> [5, 4, 6, 3, 1, 2]

var x = _.sortBy(["me", "i", "and"], 'length'); 

=> ["i", "me", "and"]

var persons = [ { 
    name : "seka", 
    age : 24 
}, 
{ 
    name : "ryo", 
    age : 52 
}, 
{ 
    name : "pxp_ss", 
    age : 32, 
} 
var orderByYoung = _.sortBy(persons, function (person) { 
    return person.age; 
}); 

=> [{"name":"seka","age":24}, {"name":"pxp_ss","age":32}, {"name":"ryo","age":52}]

条件に沿って要素の並び替えを行う

オブジェクトのプロパティでソートをかけることも可能(ex. lengthなど)

集合に関する演算

union

var a = [1, 2, 5];
var b = [5, 2, 8];
var x = _.union(a, b);

=> [1, 2, 5, 8]

2つの配列から和集合を求めることができる.

intersection

var a = [1, 2, 5];
var b = [5, 2, 8];
var x = _.intersection(a, b)

=> [2, 5]

2つの配列から積集合を求めることができる.

difference

var a = [1, 2, 5];
var b = [5, 2, 8];
x = _.difference(a, b);

=> [1]

2つの配列から差集合を求めることができる.

uniq

x = _.uniq([2, 5, 2, 10, 5]);

=> [2, 5, 10]

配列の中から重複しないものを取り出す.

オブジェクトを操作する

keys

var user = {
 name : 'pxp_ss',
 score : 80,
 web: 'http://dotinstall.com'
};
var x = _.keys(user);

=> ["name", "score", "web"]

オブジェクトのキーを取り出す事ができる.

values

var x = _.values(user);
var user = {
 name : 'pxp_ss',
 score : 80,
 web: 'http://dotinstall.com'
};

=> ['taguchi', '80', 'http://dotinstall.com']

オブジェクトのvalueを取り出すことができる.

var user = {
 name : 'pxp_ss',
 score : 80,
 web: 'http://dotinstall.com'
}; 
var x = _.invert(user);

=> { 80:"score", tacuchi:"name", "http://dotinstall.com": "web"}

キーとバリューを逆にして出力する.

has

var user = {
 name : 'pxp_ss',
 score : 80,
 web: 'http://dotinstall.com'
}; 
var x = _.has(user, "name");

=> true

引数のオブジェクトに指定したキーがあるか判定する.

返り値はtrue/false.

isEmpty, isString, isNumber, isNull, isUndefined, isNaN

var user = {
 name : 'pxp_ss',
 score : 80,
 web: 'http://dotinstall.com'
}; 
var x = _.isString(user, score);

指定したオブジェクトのプロパティの型をチェックする.

返り値はtrue/false.

※ 使い方がほとんど同じなので、まとめて覚える.

データ生成系のメソッド

range

var x = _.range(1, 5);

=> [1, 2, 3, 4]

第2引数未満の配列を生成する

var x = _.range(5);

=> [0, 1, 2, 3, 4]

0~指定した数値までの配列を生成する.

var x = _.range(1, 11, 2);

=> [1, 3, 5, 7, 9]

2飛びで1~10の配列を生成

指定した引数分スキップする.

random

var x = _.random(10);

0~10までの整数値をランダムで出力

var x = _.random(3, 10);

3 ~ 10 までの整数値をランダムで出力

escape

var x = _.escape('<script>');

=> "&lt ;script&gt ;"

<> → &lt ;, &gt ; といったように文字列をエスケープする.

times

_.times(5, function (){
    console.log("Hello")
});

// bindして、ruby チックな書き方をすることもできる
_(5).timesfunction (){
  console.log("Hello")
});

=> Helloと5回繰り返す

繰り返し処理をしたい場合に利用する

なんでこの2つが同じ動作をするのか?

メソッドを繋げたい

chain

var array = [2, 5, 10, 8];
x = _.chain(array).shuffl()
     .map(fnction (num){
         return (num * 2);
      }).value();

=> arrayの要素を2倍した値がshufflされる

メソッドを繋げて書くことができる.

value が使用されるまでラップされたオブジェクトを返し続ける.

テンプレート機能

template

var user = {
  name : 'pxp_ss',
  score:50,
  web: 'http://cotinstall.com'
};
var template = "<li><%- name %> = <%- score %></li>"
var x = _.template(template, user);

=> "

  • pxp_ss = 50
  • "

    プロパティ名を指定するとその場所に自動代入してくれる

    ・記号の種類

    • <% %> : jsを文中に書くことが出来る

    ex.)

    <% console.log("Hello") %>
    

    => Hello

    • <%= %>:文字列をそのまま出力する

    ex.)

    var list = "<li><%= name %></li>";
    _.template(list, {people: "pxp_ss"});
    

    => <li>pxp_ss</li>

    • <%- %>:文字列をエスケープして出力する

    ex.)

    var template = _.template("<b><%- value %></b>");
    template({value: '<script>'});
    

    => "<b>&lt ;script&gt ;</b>"

    ※ templateにする記号を変更することもできる

    _.templateSettings = {
      interpolate: /\{\{(.+?)\}\}/g
    };
    var template = _.template("Hello {{ name }}!");
    template({name: "pxp_ss"});
    

    => "Hello pxp_ss!"

    参考