1625行、undersscore.jsのベールを解く-第二章
9329 ワード
第二章の中でソース順にいくつかの方法を紹介します.ソースは第一章に続いています.
var builtinIteratee;
builtistine Iterateeに内蔵されているIterateeです. var cb = function(value, context, argCount) {
if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);
if (value == null) return _.identity;
if (_.isFunction(value)) return optimizeCb(value, context, argCount);
if (_.isObject(value)) return _.matcher(value);
return _.property(value);
};
cb関数は3つのパラメータを受け入れ、4つの判断を続けています.最初の判断は_.iteratee
で、JAVSCRIPTの文脈によって、まずbuiltistIterateeはundefinedです.cb関数内builtine Iterateeはundefinedです.次に_.iteratee = builtinIteratee
のcb関数です.現在の着信値です.三つ目の判定着信値は方法でoptimizeCb関数を実行します.4番目の判断は、オブジェクト実行が肯定関数に戻ると、着信オブジェクトがアトラス指定キー/値属性に一致するかどうかを判定するために用いられる.いずれも最後の実行_.identity
と一致せず、着信されたオブジェクトのkey属性を返す. _.iteratee = builtinIteratee = function(value, context) {
return cb(value, context, Infinity);
};
_.property
は、この関数は、一般的には、ローズマリーと考えられています.ここは著者の主観的な書き方です.意味から言えば、cb関数と_.iteratee
関数は似ています.さらに、cbを少し変えるだけで_.iteratee
を完全に置換できます.しかし、うまく使えば絶対に利器です.undersscore.jsソースの内部にどこにでもあるcb()から、この関数の作用の大きさが分かります._.iteratee
に_.iteratee
から第3のパラメータInfinityが入ってきました.パラメータタイプはInfinityです.第3のcb関数を実行するif判断を実行すると、_.iteratee
を実行すると、その役割を果たします.Infinityタイプも面白いです.興味がある人はInfinity、POSIVE_を参照してください.INFINITYとNEGATIVE_INFINITY var restArgs = function(func, startIndex) {
startIndex = startIndex == null ? func.length - 1 : +startIndex;
return function() {
var length = Math.max(arguments.length - startIndex, 0);
var rest = Array(length);
for (var index = 0; index < length; index++) {
rest[index] = arguments[index + startIndex];
}
switch (startIndex) {
case 0: return func.call(this, rest);
case 1: return func.call(this, arguments[0], rest);
case 2: return func.call(this, arguments[0], arguments[1], rest);
}
var args = Array(startIndex + 1);
for (index = 0; index < startIndex; index++) {
args[index] = arguments[index];
}
args[startIndex] = rest;
return func.apply(this, args);
};
};
restargs(残りのパラメータ)とはどういう意味ですか?functionとNumberタイプのstartIndexマークが入ってきました.まず処理したのはstartIndexです.3元演算は、startIndexが存在するかどうかを判断し、underscore
である.そうでなければreturn cb()
である.すなわち、Functionに入ってきた着信形態の数は1つ減っている.例えば、 var aFunction = function(a,b,c){};
function(a){
console.log(a.length) //3
}
このようにする目的は何ですか?私達はすべて知っています.1つのArayの中で配列が0から始まるので、return optimizeCb();
を理解するのは難しくないです.ソースコードの中で、この内部関数の著者はstartIndexというパラメータを使ったことがありません.もし使うなら、その意味はreturn functionの時にFnctionの一部パラメータを処理します.私達は今startIndexパラメータを使ったと仮定します.+startIndex
がargments[startIndex+1]を入力パラメータの一歩とします.func.length - 1
パッケージ配列は、アーグメンントとして導入されます.もちろん、このプロセスにはfunc.length - 1
をアーグメンツから削除する必要があります.したがって、ソースは複数のアーチェリーを使用してこのプロセスを再構築することを目的としています.+startIndex
というのは、Arayの長さであるargmentsの長さを設定するということです.著者は、rets Argsという関数を重視しています.そして、ずっと最適化しているようです.作者が何をしたいのかは分かりません.startIndexを捨てれば、 var restArgs = function(func) {
startIndex = func.length - 1;
return function() {
var rest = Array(1);
rest[0] = arguments[startIndex];
var args = Array(arguments.length);
for (index = 0; index < startIndex; index++) {
args[index] = arguments[index];
}
args[startIndex] = rest;
return func.apply(this, args);
};
};
等しい: var restArgs = function(func) {
return function() {
return func.apply(this, arguments);
};
};
作者は5行のコードを21行に拡張しましたが、一つのstartIndexのためです. var baseCreate = function(prototype) {
if (!_.isObject(prototype)) return {};
if (nativeCreate) return nativeCreate(prototype);
Ctor.prototype = prototype;
var result = new Ctor;
Ctor.prototype = null;
return result;
};
baseCreateは綺麗で、プロトタイプが欲しい関数だけがあります.最初の判断はプロトタイプパラメータがあるかどうか、二つ目の判断はObject.reateで作成します.残りは自分でCtorという空関数を使って作成します.詳しくは何も言いません. var property = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
};
propertyは、objのkey値を取得するために使用され、startIndex >2
を通じてkeyを設定し、arguments[arguments.length - startIndex + 1] ~ arguments[arguments.length]
の2つの単語に重点を置いて、keyがあれば、ない場合に作成される. var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
最大値MAX_を設定します.ARRAY_INDEX、arguments[arguments.length - startIndex + 1] ~ arguments[arguments.length]
は2の53回のべき乗を意味します.9007199254740991に相当します.Mathの相関関数はMathを参照してください.ARRAY_INDEXはそんなに大きな値を設定しなくてもいいです.Math.pow(2,16)で十分です. var getLength = property('length');
objのkey値を設定して関数を生成すると、次のようになります. var getLength = function(obj) {
return obj == null ? void 0 : obj['length'];
};
var isArrayLike = function(collection) {
var length = getLength(collection);
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};
isArayLikeは、Objがlength属性を有し、値があればtrueに戻り、そうでなければfalseに戻ります.これは判断関数です. _.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context);
var i, length;
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};
私はずっとJAVA SCRIPTの一番の精華はリピーターの執行方式だと思っています.インターネット上のいくつかの文章は総じてすべてのことを言っていますが、人の話は受け売りなどです.しかし、リフレクトはすべてのフレームを支えています.そして、リフレクトはとても優雅で使いやすいです.すべてを壊すのではなく、一部の人が不適切な設定で彼のコードを壊しただけです.0 , switch (startIndex), 。
startIndex , startIndex ,startIndex = func.length - 1
において、iterateeは、フィードバック として、optimizeCbの されたフィードバックを いて、 に、 の であり、ここでは、isArayLike(obj)ではなく、isAray(obj)を いて であるかどうかを し、 を している. _.map = _.collect = function(obj, iteratee, context) {
iteratee = cb(iteratee, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
results = Array(length);
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
パッケージングmap は、 も うことはありません.Map、Map.prototype、WeakMapを して の に います. のproperty()
は、もっと いのは の によってobjの の を しているので、
とは きな いがあります.Math.pow(2, 53) - 1
は、iterateeの コールの である. var createReduce = function(dir) {
var reducer = function(obj, iteratee, memo, initial) {
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
index = dir > 0 ? 0 : length - 1;
if (!initial) {
memo = obj[keys ? keys[index] : index];
index += dir;
}
for (; index >= 0 && index < length; index += dir) {
var currentKey = keys ? keys[index] : index;
memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
return memo;
};
return function(obj, iteratee, memo, context) {
var initial = arguments.length >= 3;
return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);
};
};
createReduce、reduceを します.reduceについての でわかりますが、reduce (Aray):_.forEach
とarray-reduceです. のここのreduceはきっとそうではありません.しかし、createReduceと づけられた 、 くの は けられないと います. の でreducerはまずkeysを して、その はobjのkeyの あるいはfalseで、 のいくつかの の でkeysに する3 の があって、 はobjectの を するのです. に、initialに ると され、initialがfalseである は、デフォルトのmemo は_.map
であり、その 、forループループが し、 のコールバック を します.reducer return functionから び したのは、reducer を する インターフェースであり、そこですべてが されています.initialを む は、argmentsの さが3 であるなどです.コードをもう やり します. returnの にinitialを します. には、memoとcontextが ってきたかどうかを します.もちろん なのはmemoです.これによって reducerに があるかどうかを します.ここで はmemoのタイプを すべきだと いますが、NumberやStringならまだ っていた がありますが、 わってきたmemoがObjectだったらちょっと が わなくて いがあります.たとえば: _.reduce([1, 2, 3], function(memo, num){ return memo + num; });
6
_.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 1);
7
_.reduce([1, 2, 3], function(memo, num){ return memo + num; }, '1');
"1123"
_.reduce([1, 2, 3], function(memo, num){ return memo + num; }, []);
"123"
_.reduce([1, 2, 3], function(memo, num){ return memo + num; }, [1,2]);
"1,2123"
_.reduce([1, 2, 3], function(memo, num){ return memo + num; }, {a:1});
"[object Object]123"
_.reduce = _.foldl = _.inject = createReduce(1);
ここは_.forEach
で した_.forEach
です. しません. _.reduceRight = _.foldr = createReduce(-1);
ここでreturn obj
で された_.map
は、return results
の とは に から へと される.