Last active
December 2, 2015 10:29
-
-
Save mitsuru793/855e12e61867c2d855d1 to your computer and use it in GitHub Desktop.
Underscore.jsの_.mixinメソッドをコードリーディングします。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// mixinの挙動をコメントで記したものです。 | |
var people = [{name: 'mike', age: 18}, {name: 'jane', age: 21}, {name: 'lake', age: 32}]; | |
var sortedPeople = _.chain(people) | |
.sortBy(function(poeple){ return people.age; }) | |
.first() | |
.value(); | |
// 下記は、上記のコードを実行した場合のコメントです。 | |
// sortByのところでステップインした時のものです。 | |
// 式の次の行に、実行後の変数の中身を記載しています。 | |
// mixinは_functionオブジェクトに、objにある関数への参照をprototypeに渡します。 | |
_.mixin = function(obj) { | |
_.each(_.functions(obj), function(name) { | |
var func = _[name] = obj[name]; | |
_.prototype[name] = function() { | |
// chainで繋げた場合は、sortByはここから始まります。 | |
// name = 'sortBy' | |
var args = [this._wrapped]; | |
// 3人の配列。無名関数に渡した配列です。 | |
// args = [Array[3]] | |
// pushはArray.prototype.pushのエイリアスとなっています。 | |
push.apply(args, arguments); | |
// sortByに渡した無名関数を、配列の要素として加えます。 | |
// args = [[Array[3], function] | |
// func = _.sortBy | |
// this = _のインスタンス 中身は_wrapped:Array[3], _chain:trueです。 | |
// func.apply(_, args)は書き換えると、_.func(args)という意味です。 | |
// メソッド名が固定ではないので、このような書き方をしています。 | |
// applyだけでインスタンスメソッドの実行はできていますが、戻り値をchainResultに渡します。 | |
return chainResult(this, func.apply(_, args)); | |
}; | |
}); | |
}; | |
// mixinの定義直後に、_のprototypeに、_にバインドしてある関数を結びつけています。 | |
// これを行わないと、_のインスタンスで各メソッドが使えません。 | |
_.mixin(_); | |
// _のメソッドでチェーン可能なら、objを_でラップして返します。 | |
// 関数の戻り値を、chainした結果を返します。 | |
// chainを使っていない場合は、そのままobjを返します。 | |
var chainResult = function(instance, obj) { | |
// instance._chainは、_.chainメソッドが使われて生成された、 | |
// _のインスタンスかどうか判定する真理値です。(true/false) | |
// この条件によって、_.chainで繋げられているかがわかります。 | |
// trueの場合に実行されるchainには、引数が渡されておりません。 | |
// ここから、上記のsortByが実行される場所にステップインします。 | |
// chainが_のインスタンスメソッドだからです。 | |
// 上記のfunc.apply(_, args)によって、chainにはpeopleの配列が渡ります。 | |
// また、peopleは_にラップされます。 | |
return instance._chain ? _(obj).chain() : obj; | |
}; | |
// objを_でラップして、_chainプロパティを持たせます。 | |
// _chainの中身がいじられるのここだけです。 | |
// つまり、_chainはchainメソッドを使ったかのフラグです。 | |
_.chain = function(obj) { | |
var instance = _(obj); | |
instance._chain = true; | |
return instance; | |
}; | |
// objを_でラップします。 | |
// ここの詳細は、長くなるので別途ブログで記事にします。 | |
var _ = function(obj) { | |
// _のインスタンスなら引数objを返します | |
if (obj instanceof _) return obj; | |
// this(実行コンテキスト)が_のインスタンスではない場合は、_メソッドで再生成をします。 | |
if (!(this instanceof _)) return new _(obj); | |
// 引数objが_のインスタンスではなく、this(実行コンテキスト)が_のインスタンスの場合 | |
this._wrapped = obj; | |
}; | |
// 最後のvalueメソッドだけは、mixinの中の無名関数にはステップインしません。 | |
// 理由は、valueは静的に予めprototypeに定義されたメソッドだからです。 | |
// mixinの無名関数にステップインするものは、 | |
// mixinによって、prototypeに動的に定義されたものだけです。 | |
_.prototype.value = function() { | |
return this._wrapped; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment