ページ

2012年10月15日月曜日

Underscore.js について纏めてみた


Underscore.jsは、便利なユーティリティ関数を詰め合わせたライブラリです。


大きく6つの機能に分類される



【コレクション】

each
~ listの要素をイテレートする。すべての要素はiterator関数にyieldされる。
  iteratorには(element, index, list)の3つの引数が渡される。
  もしlistがJavascript Objectだった場合は(value, key, list)になる。
_.each([1, 2, 3], function(num){ alert(num); });
=> alerts each number in turn...
_.each({one : 1, two : 2, three : 3}, function(num, key){ alert(num); });
=> alerts each number in turn...

map
~ listのすべての要素を操作関数(iterator)でマッピングし、新しい配列を作る。
  もしlistがJavascript Objectだった場合、iteratorへの引数は(value, key, list)になる。
_.map([1, 2, 3], function(num){ return num * 3; });
=> [3, 6, 9]
_.map({one : 1, two : 2, three : 3}, function(num, key){ return num * 3; });
=> [3, 6, 9]

reduce
~ listの要素を1つの値に集約する。memoが初期値。
  iteratorはステップごとに値を返さなければいけない。
var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
=> 6

reduceRight
~ 右方向からのreduce。
var list = [[0, 1], [2, 3], [4, 5]];
var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
=> [4, 5, 2, 3, 0, 1]

find
~ リストの要素の中から、一番最初に真値テスト(iterator)を通過したものを返す。
var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> 2

filter
~ リストの要素の中から、真値テスト(iterator)を通過したものを返す。
var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]

reject
~ リストの要素の中から、真値テスト(iterator)を通過しなかったものを返す。selectの反対。
var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [1, 3, 5]

all
~ リストの要素がすべて真値テスト(iterator)を通過した場合、trueを返す。
  そうでない場合はfalseを返す。
  iteratorが与えられなかった場合、代わりに真理値が使用される。
_.all([true, 1, null, 'yes'], _.identity);
=> false

any
~ listの要素が1つでも真値テストを通過した場合、trueを返す。そうでない場合はfalseを返す。
_.any([null, 0, 'yes', false]);
=> true

include
~ valueがlistに含まれている場合、trueを返す。そうでない場合はfalseを返す。
  値の比較は===演算子で行われる。
_.include([1, 2, 3], 3);
=> true

invoke
~ listの各要素に対してmethodNameで指定した関数を実行する。
  *argumentsは、指定された関数に引き渡される。
_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
=> [[1, 5, 7], [1, 2, 3]]

pluck
~ mapの便利バージョン。指定したプロパティ名に対応する値を集める。
var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
_.pluck(stooges, 'name');
=> ["moe", "larry", "curly"]

max
~ listの中の最大値を求める。
  iteratorが渡された場合、iteratorの返り値がランク付けの基準として使用される。
var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
_.max(stooges, function(stooge){ return stooge.age; });
=> {name : 'curly', age : 60};

min
~ listの中の最小値を求める。
  iteratorが渡された場合、iteratorの返り値がランク付けの基準として使用される。
var numbers = [10, 5, 100, 2, 1000];
_.min(numbers);
=> 2

sortBy
~ 各要素をiteratorの返り値でランク付けし、それと元にソートされたlistを返す。
_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
=> [5, 4, 6, 3, 1, 2]

groupBy
_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
=> {1: [1.3], 2: [2.1, 2.4]}
_.groupBy(['one', 'two', 'three'], 'length');
=> {3: ["one", "two"], 5: ["three"]}

sortedIndex
~ 二分探索で、valueがlistの挿入されるべき位置を調べ、それを返す。
  iteratorが渡された場合、iteratorの返り値がランク付けの基準として使用される。
_.sortedIndex([10, 20, 30, 40, 50], 35);
=> 3

shuffle
_.shuffle([1, 2, 3, 4, 5, 6]);
=> [4, 1, 6, 3, 5, 2]

toArray
~ list(イテレートできるものならなんでも)をArrayに変換する。引数を変形するのに便利。
(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
=> [2, 3, 4]

size
~ listに含まれている要素の数を返す。
_.size({one : 1, two : 2, three : 3});
=> 3



【配列】

first
~ 配列の一番目の要素を返す。nを指定しすると、先頭からn番目の要素までの配列を返す。
_.first([5, 4, 3, 2, 1]);
=> 5

initial
_.initial([5, 4, 3, 2, 1]);
=> [5, 4, 3, 2]

last
~ 配列の最後にある要素を返す。
_.last([5, 4, 3, 2, 1]);
=> 1

rest
~ 先頭の要素を取り除いた配列を返す。
  indexを指定すると、index番目以降の要素を配列として返す。
_.rest([5, 4, 3, 2, 1]);
=> [4, 3, 2, 1]

compact
~ 曖昧な値であるfalse, null, 0, "", undefinedを取り除いた配列を返す。非破壊的。
_.compact([0, 1, false, 2, '', 3]);
=> [1, 2, 3]

flatten
~ 多次元配列を一次元化する。非破壊的。
_.flatten([1, [2], [3, [[4]]]]);
=> [1, 2, 3, 4];
_.flatten([1, [2], [3, [[4]]]], true);
=> [1, 2, 3, [[4]]];

without
~ valuesを取り除いた配列を返す。===演算子で比較される。非破壊的。
_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
=> [2, 3, 4]

union
_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

intersection
~ 複数の配列の共通集合を返す。
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]

difference
_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

uniq
~ 配列から重複を取り除く。===演算子で比較される。
  配列がソートされている場合は、isSrotedをtrueにすると処理が早くなる。非破壊的。
_.uniq([1, 2, 1, 3, 1, 4]);
=> [1, 2, 3, 4]

zip
~ 複数の配列の、同じ位置にある要素をマージする。
_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
=> [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]

indexOf
~ 配列にvalueが含まれていた場合、valueが一番最初に現れた位置を返す。
  含まれていなかった場合は-1を返す。
  配列がソートされている場合は、isSrotedをtrueにすると処理が早くなる。
_.indexOf([1, 2, 3], 2);
=> 1

lastIndexOf
~ 配列にvalueが含まれていた場合、valueが一番最後に現れた位置を返す。
  含まれていなかった場合は-1を返す。
_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
=> 4

range
~ startからstopまでstepずつ増加(または減少)する整数のリストを作る。排他的。
  startのデフォルト値は0。stepのデフォルト値は1。
_.range(10);
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11);
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5);
=> [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1);
=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
_.range(0);=> []



【関数】

bind
~ オブジェクトを関数にバインドする。
  関数が呼ばれたとき、thisがobjectの値をとるということ。カリー化。
var func = function(greeting){ return greeting + ': ' + this.name };
func = _.bind(func, {name : 'moe'}, 'hi');
func();
=> 'hi: moe'

bindAll
~ 複数の関数をオブジェクトにバインドする。
  イベントハンドラーに関数をバインドするときに便利。
var buttonView = {
    label   : 'underscore',
    onClick : function(){
        alert('clicked: ' + this.label);
    },
    onHover : function(){
        console.log('hovering: ' + this.label);
    }
};
_.bindAll(buttonView);
jQuery('#underscore_button').bind('click', buttonView.onClick);
=> When the button is clicked, this.label will have the correct value...

memoize
~ 関数の計算結果をキャッシュする。メモ化。
  hasFunctionが指定された場合、結果をストアするためのハッシュキーとして利用される。
  hasFunctionのデフォルト値は一番最初の引数。
var fibonacci = _.memoize(function(n) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
});

delay
~ setTimeoutのように、ミリ秒後に関数を呼び出す。
  argumentsを指定した場合、それが呼び出される関数に引き渡される。
var log = _.bind(console.log, console);
_.delay(log, 1000, 'logged later');
=> 'logged later' // Appears after one second.

defer
~ コールスタックが空になるまで、関数の呼び出しを遅延させる。
  delay = 0でsetTimeoutを使う場合と同じ。
  複雑な計算を行ったり、UIスレッドをブロックせずにまとまったHTMLレンダリングを行いたいときに便利。
_.defer(function(){ alert('deferred'); });
// Returns from the function before the alert runs.

throttle
~ スロットル化された関数を返す。
  ラップされた関数はwaitミリ秒に多くても一度しか実行されない。
  レートが制限されたイベントを起こすのに便利。
var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);

debounce
~ 関数が実行されてからwaitミリ秒が経過するまで、繰り返しの呼び出しを抑止する。
  何らかの入力がストップしたときに実行される振る舞いを実装したいときに便利。
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

once
~ 一度しか実行されない関数を作成する。
  修正された関数の二度目以降の呼び出しは、なんの影響も与えず、最初に呼び出されたときの返り値を返す。
  初期化処理に便利。
var initialize = _.once(createApplication);initialize();
initialize();

after
var renderNotes = _.after(notes.length, render);
_.each(notes, function(note) {
    note.asyncSave({success: renderNotes});
});

wrap
~ 最初の引数で指定した関数をwrapper関数の中にラップする。
  wrapper関数には指定された関数の実行の前後で行われる処理を記述することができる。
var hello = function(name) { return "hello: " + name; };
hello = _.wrap(hello, function(func) {
    return "before, " + func("moe") + ", after";
});
hello();
=> 'before, hello: moe, after'

compose
~ 複数の関数の合成関数を返す。関数は次の関数の返り値を引数としてとる。
  関数f(), g(), h()を合成しすると関数f(g(h()))ができる。
var greet    = function(name){ return "hi: " + name; };
var exclaim  = function(statement){ return statement + "!"; };
var welcome = _.compose(exclaim, greet);
welcome('moe');
=> 'hi: moe!'



【オブジェクト】


keys
~ objectのプロパティ名をすべて取り出す。
_.keys({one : 1, two : 2, three : 3});
=> ["one", "two", "three"]

values
~ objectのプロパティ値をすべて取り出す。
_.values({one : 1, two : 2, three : 3});
=> [1, 2, 3]

functions
~ objectが持つすべての関数プロパティ名をソートして返す。
_.functions(_);
=> ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ...

extend
~ soucesオブジェクトのすべてのプロパティをdestinationオブジェクトにコピーする。
  sourcesの中に同じ名前のプロパティが含まれていた場合、より後のもので上書きされる。
_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}

pick
_.pick({name : 'moe', age: 50, userid : 'moe1'}, 'name', 'age');
=> {name : 'moe', age : 50}

defaults
~ objectがdefaultsオブジェクトのプロパティを持っていない場合、objectにそのdefaultsオブジェクトのプロパティを付与する。
var iceCream = {flavor : "chocolate"};
_.defaults(iceCream, {flavor : "vanilla", sprinkles : "lots"});
=> {flavor : "chocolate", sprinkles : "lots"}

clone
~ objectのシャローコピーうを作る。ネストされたオブジェクトや配列は、参照コピーされる。
_.clone({name : 'moe'});
=> {name : 'moe'};

tap
_.chain([1,2,3,200])
    .filter(function(num) { return num % 2 == 0; })
    .tap(alert)
    .map(function(num) { return num * num })
    .value();
=> // [2, 200] (alerted)
=> [4, 40000]

has
_.has({a: 1, b: 2, c: 3}, "b");
=> true

isEqual
var moe   = {name : 'moe', luckyNumbers : [13, 27, 34]};
var clone = {name : 'moe', luckyNumbers : [13, 27, 34]};
moe == clone;
=> false

_.isEqual(moe, clone);
=> true

isEmpty
_.isEmpty([1, 2, 3]);
=> false
_.isEmpty({});
=> true

isElement
_.isElement(jQuery('body')[0]);
=> true

isArray
(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true

isObject
_.isObject({});
=> true
_.isObject(1);
=> false

isArguments
(function(){ return _.isArguments(arguments); })(1, 2, 3);
=> true
_.isArguments([1,2,3]);
=> false

isFunction
_.isFunction(alert);
=> true

isString
_.isString("moe");
=> true

isNumber
_.isNumber(8.4 * 5);
=> true

isFinite
_.isFinite(-101);
=> true
_.isFinite(-Infinity);
=> false

isBoolean
_.isBoolean(null);
=> false

isDate
_.isDate(new Date());
=> true

isRegExp
_.isRegExp(/moe/);
=> true

isNaN
_.isNaN(NaN);
=> true
isNaN(undefined);
=> true
_.isNaN(undefined);
=> false

isNull
_.isNull(null);
=> true
_.isNull(undefined);
=> false

isUndefined
_.isUndefined(window.missingVariable);
=> true



【ユーティリティ】


noConflict
var underscore = _.noConflict();

identity
var moe = {name : 'moe'};
moe === _.identity(moe);
=> true

times
_(3).times(function(){ genie.grantWish(); });

mixin
_.mixin({
    capitalize : function(string) {
        return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
    }
});
_("fabio").capitalize();
=> "Fabio"

uniqueId
_.uniqueId('contact_');
=> 'contact_104'

escape
_.escape('Curly, Larry & Moe');
=> "Curly, Larry & Moe"

result
var object = {cheese: 'crumpets', stuff: function(){ return 'nonsense'; }};
_.result(object, 'cheese');
=> "crumpets"
_.result(object, 'stuff');
=> "nonsense"

template
var compiled = _.template("hello: <%= name %>");
compiled({name : 'moe'});
=> "hello: moe"

var list = "<% _.each(people, function(name) { %> <li><%= name %></li> <% }); %>";
_.template(list, {people : ['moe', 'curly', 'larry']});
=> "<li>moe</li><li>curly</li><li>larry</li>"

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

var compiled = _.template("<% print('Hello ' + epithet); %>");
compiled({epithet: "stooge"});
=> "Hello stooge."

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

_.template("Using 'with': <%= data.answer %>", {answer: 'no'}, {variable: 'data'});
=> "Using 'with': no"

<script>
    JST.project = <%= _.template(jstText).source %>;
</script>
※注意:値をバインドする際に<%= を使いがちですが、サニタイズの必要がある場合は、<%- を利用してHTML文字をエスケープするようにしましょう。


【チェーン】

chain
var stooges = [{name : 'curly', age : 25}, {name : 'moe', age : 21}, {name : 'larry', age : 23}];
var youngest = _.chain(stooges)
    .sortBy(function(stooge){
        return stooge.age;
    })
    .map(function(stooge){
        return stooge.name + ' is ' + stooge.age;
    })
    .first()
    .value();
=> "moe is 21"

value
_([1, 2, 3]).value();
=> [1, 2, 3]

公式サイト
http://underscorejs.org/


0 件のコメント:

コメントを投稿