Underscoreソースシリーズを覗く-冒頭
8352 ワード
冒頭の説明
はい、あなたに見せて、また車輪を作り始めました.ははは、車輪を作るのは私たちはまじめです~
ソースコードを読む必要があります.Underscoreは関数式のプログラミングを整理したばかりなので、自分がソースコードを読む経験があまりないので、まずUnderscoreを持って手を練習して、先輩たちについて歩いて、勉強します.同じ時にjsの基礎を固めることができて、ソースコードの中からもっと多くの符号化の技巧を学ぶことができます
Underscoreソースコードの読み取りは、ほぼ公式ドキュメントに従って作成されます.できるだけ各関数の書き方を説明し、そこから大神のコード力を収穫できることを望んでいます.
github:Personal_Blog
目次を読む
ソース読解
全体構造、変数の紹介
(function(){}())
通常の操作は、jQuery一毛と同じように、IIFEを通じて業務ロジックを包み、目的は簡単です:1、グローバル汚染を避ける.2、プライバシー保護
var root = typeof self == 'object' && self.self === self && self ||
typeof global == 'object' && global.global === global && global ||
this ||
{};
var previousUnderscore = root._;
globalとselfでnode環境かwindow環境かを判断するのは、はっきり言って、グローバル変数を得るためです.グローバルな変数が必要ですだから衝突を防ぐために、ここでrootを手に入れた後、前のrootを一時保存します.
var ArrayProto = Array.prototype, ObjProto = Object.prototype;
var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
var push = ArrayProto.push,
slice = ArrayProto.slice,
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty;
var nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeCreate = Object.create;
var Ctor = function(){};
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
};
if (typeof exports != 'undefined' && !exports.nodeType) {
if (typeof module != 'undefined' && !module.nodeType && module.exports) {
exports = module.exports = _;
}
exports._ = _;
} else {
root._ = _;
}
_.VERSION = '1.8.3';
Underscore自体は多くのオリジナルjsの方法に依存するため,ここではプロトタイプチェーンのルックアップ性能の消耗を避けるために,Underscoreは局所変数によっていくつかの一般的なオブジェクトと方法を保存する.パフォーマンスの向上、オブジェクト・メンバーのアクセスの深さの低減、コードの冗長性の低減が可能です.
次のCtorと_オブジェクト向けに用意されています.
反復
var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func;
switch (argCount == null ? 3 : argCount) {
case 1: return function(value) {
return func.call(context, value);
};
case 3: return function(value, index, collection) {
return func.call(context, value, index, collection);
};
case 4: return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
return function() {
return func.apply(context, arguments);
};
};
var builtinIteratee;
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) && !_.isArray(value)) return _.matcher(value);
return _.property(value);
};
_.iteratee = builtinIteratee = function(value, context) {
return cb(value, context, Infinity);
};
ここでの反復は、Underscoreでは、コマンド式のプログラミング方法を変更する必要があります.具体的には、私が前に書いた関数式のプログラミングに関する文章を見ることができます.
だからここで言いたいのは反復を巡ることです.
var results = _.map([1,2,3],function(elem){
return elem*2;
}); // => [2,4,6]
_.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の2番目のパラメータはiterateeで、彼は関数、オブジェクト、さらには文字列かもしれません.
optimizeCb()
上記の解析では、入力されたvalueが関数である場合、valueはoptimizeCbという内蔵関数を経て最終的なiterateeを得ることができることを知っています.
var cb = function (value, context, argCount) {
// ...
if (_.isFunction(value)) return optimizeCb(value, context, argCount);
// ...
};
したがって,ここでのoptimizeCbは必ずコールバックを最適化する役割を果たす.
// ,
var optimizeCb = function(func, context, argCount) {
// void 0 undefined
if (context === void 0) return func;
switch (argCount == null ? 3 : argCount) {
case 1: return function(value) {
// argCount 0 , , value
return func.call(context, value);
};
// The 2-parameter case has been omitted only because no current consumers
// 3 ( , , ).
case 3: return function(value, index, collection) {
return func.call(context, value, index, collection);
};
// 4 ( ( reducer ), , , )
case 4: return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
return function() {
return func.apply(context, arguments);
};
};
全体のコードは非常に明確で、最適化されるコールバック関数func、コンテキストcontext、および反復コールバックに必要なパラメータの数です.
上記の最適化されたコールバックは、異なる場所で使用される異なる反復に関連する.ここはしばらく置いておきます.ソースコードを1回待った後、反復を使う場所を1つずつ見て、振り返ってみると、多くのことがわかります.
restパラメータ
ES 6では不定パラメトリックメソッドを定義するときにこう書くことができます
let a = (b,...c)=>{
console.log(b,c);
}
しかし、その前にUnderscoreは独自のresetを実現し、以下のように使用した.
function a(a,b,c,d,e){
console.log(a,b,c,d,e)
}
let aa = restArgs(a);//let aa = restArgs(a,4)
aa(1,2,3,4,5,6,7,8,8)
restArgsの実装を見てみましょう.
var restArgs = function(func, startIndex) {
//
startIndex = startIndex == null ? func.length - 1 : +startIndex;
return function() {
//
//length
var length = Math.max(arguments.length - startIndex, 0),
rest = Array(length),
index = 0;
for (; index < length; index++) {
rest[index] = arguments[index + startIndex];
}
// 。 rest ,
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);
}
// startIndex,
//
var args = Array(startIndex + 1);
for (index = 0; index < startIndex; index++) {
args[index] = arguments[index];
}
//
args[startIndex] = rest;
return func.apply(this, args);
};
};
オブジェクト向け
オブジェクト向けについては、ここではあまり説明しませんが、javasript設計モードのオブジェクト向けを参照してください.
彼の継承の実現を直接見ましょう.
var Ctor = function(){};
//
var baseCreate = function(prototype) {
if (!_.isObject(prototype)) return {};
// nativeCreate = Object.create;
if (nativeCreate) return nativeCreate(prototype);
Ctor.prototype = prototype;
var result = new Ctor;
Ctor.prototype = null;
return result;
};
Es 5ではオブジェクトを作成する方法がありますcreate .
function Animal(name){
this.name = name;
}
Animal.prototype.eat = function(){
console.log(this.name,' ');
}
var dog = Object.create(Animal.prototype);
dog.name = " ";
dog.eat();
OK、多分上からcreateの役割が見えます.
baseCreateでは,まず対象か否かを判断し,そうでなければ終了する.ブラウザ機能は、Objectを備えるか否かを検出する.createメソッド、備えれば使用します.それ以外の場合は、寄生継承を使用してオブジェクトを作成します.なお、baseCreateは、Objectのようにプロトタイプ継承のみをサポートする.createのようにプロパティリストを渡します.
終わりの言葉
冒頭ではCollection Functionsの上のコード部分を簡単に紹介します.Collection Functionの各メソッドの実装を紹介する前に、次のツールメソッドの作成方法を見てみましょう.
確かに車輪を作っているが、もっと自分で優秀なコードを描きたいだけだ.