JS階段――アンダースコアソース(1)
10612 ワード
目次
説明
undersscoreは、JavaScriptのツールライブラリとして機能式プログラミングに多くの方法を提供していますので、ソースを読むのは関数式プログラミングを理解するのに適しています.筆者が読んだのは1.8.3版で、コードとコメントはすべて手書きで書いています.また、インターネットの資料も参考にしました.そして、es 6のletを使ってvarに代わって、読み終わったらカプセル化されたjsファイルをgithubに置きます.
_.VERION='1.8.3';
直ちに関数を実行します
undersscoreの最外層は即座に関数を実行して、すべての内容は関数の内部に置いて、利用する思想は閉じます.
グローバル変数宣言
var root=this
しかし、1.8.3バージョンでgithubのソースコードを調べました.一番上のパッケージ方式であることが分かりました.
1、前方互換厳格モードで、厳格モードで直接にthisを使うとundefinedが得られます.これはecma 262第5版の中で、new以外のオブジェクトのthisをグローバルの名前空間に向けて誤魔化さないように、undefinedに設定したからです.2、WebWorkカーをサポートするために、WebWorkカーでselfが使えますが、windowは使えません.
もう一つの注意すべき点は:
(typeof self='object')
ここで使うのは==ではなく、==です.と==の違いは不完全などで、一つは全部で、==を使う利点は転義できます.グローバル名前空間は必ずしも完全に等価が対象とは限らないので、これはブラウザの実現と関係があります.
名前の衝突を避ける
var under scorecache=u.noConflick()
undersscoreの名前を再定義します.
_.(初期化)
nodeサービス中:
AMDJ
原型を保存
オブジェクト作成の特殊処理
コールバック処理
これを見る前に、void 0とはどういう意味ですか?引用文の由来はJavaScriptにあります.もしundefinedかどうかを判断したいなら、私たちは通常こう書きます.
次に、セット反復に対するコールバック処理である.
説明
undersscoreは、JavaScriptのツールライブラリとして機能式プログラミングに多くの方法を提供していますので、ソースを読むのは関数式プログラミングを理解するのに適しています.筆者が読んだのは1.8.3版で、コードとコメントはすべて手書きで書いています.また、インターネットの資料も参考にしました.そして、es 6のletを使ってvarに代わって、読み終わったらカプセル化されたjsファイルをgithubに置きます.
_.VERION='1.8.3';
直ちに関数を実行します
undersscoreの最外層は即座に関数を実行して、すべての内容は関数の内部に置いて、利用する思想は閉じます.
(function ( ) {...}) ()
は独立した作用領域を形成しています.このような利点は全体を汚染しなくてもいいし、他の要因が内部関数に与える影響も防げます.グローバル変数宣言
let root = (
(typeof self == 'object') &&
// self window ,
(self.self === self) &&
// self, self , window
(self)
// , window, window root, self window
) ||
(
(typeof global == 'object') &&
// global node
(global.global === global) &&
// gloabl, global
(global)
// , global, global root
) ||
(this);
// , this, window , global node
このセグメントコードは主に環境のグローバル名前空間を確認し、変数rootに値を与えます.注意に値するのは、ネット上の多くのソースコードの分析はvar root=this
しかし、1.8.3バージョンでgithubのソースコードを調べました.一番上のパッケージ方式であることが分かりました.
1、前方互換厳格モードで、厳格モードで直接にthisを使うとundefinedが得られます.これはecma 262第5版の中で、new以外のオブジェクトのthisをグローバルの名前空間に向けて誤魔化さないように、undefinedに設定したからです.2、WebWorkカーをサポートするために、WebWorkカーでselfが使えますが、windowは使えません.
もう一つの注意すべき点は:
(typeof self='object')
ここで使うのは==ではなく、==です.と==の違いは不完全などで、一つは全部で、==を使う利点は転義できます.グローバル名前空間は必ずしも完全に等価が対象とは限らないので、これはブラウザの実現と関係があります.
名前の衝突を避ける
let previousUnderscore = root._; //
_ previousUnderscore
previous Underscoreは、字面から「以前のundersscore」と理解しています.最初はこの文の意味が分かりませんでしたが、最初から最後まで一つのところにprevious Underscoreが使われました._.noConflict = function() {
root._ = previousUnderscore;
return this;
};
// noConflict
衝突が発生した場合は、例えばvar under scorecache=u.noConflick()
undersscoreの名前を再定義します.
_.(初期化)
let _ = function (obj) {
if (obj instanceof _){
return obj;
}
// obj ·_· , obj
if (!(this instanceof _)) {
return new _(obj);
}
// `_`
// new ,
this._wrapped = obj;
// obj this._wrapped
};
実は、コア関数_
は、実は構造関数であり、new呼び出しのない構造関数をサポートしています.関数スタイルのコードを使うと大きな影響はありませんが、オブジェクトスタイル向けのコードを使うと、ここではユーザーがnewを呼び出す手間が省けます.nodeサービス中:
if (typeof exports != 'undefined' && !exports.nodeType) {
if (typeof module != 'undefined' && !module.nodeType && module.exports) {
exports = module.exports = _;
}
exports._ = _;
} else {
root._ = _;
}
これはNode.jsにおける共通モジュールの実装方法であり、exportが存在するかどうかを判断することによって、局所変数_を決定する.exportsに割り当てられています.ちなみにAMD規格、CMD規格とUMD規格、Underscore.jsはAMDをサポートしています.ソースの末尾に定義があります.ここで簡単に述べます.AMDJ
define(['underscore'], function (_) {
//todo
});
cmd:Common Module Definition/draft、CMDモジュール定義仕様var _ = require('underscore');
module.exports = _;
ちなみに、nodeTypeを使ってexportsとmoduleを確保するのはHTMLの要素ではない.原型を保存
let ArrayProto = Array.prototype,
ObjProto = Object.prototype,
SymbolProto = ((typeof(Symbol)) !== ("undefined")) ? (Symbol.prototype) : (null);
// , ,
let push = ArrayProto.push,
slice = ArrayProto.slice,
// slice ,
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty;
// , ,
// ( )
let nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
//
nativeCreate = Object.create;
// create , create
//ES5 , , underscore
ちなみに、var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
2009年のES 5は6種類の言語タイプを規定しています.Null Udefined Number Boolean String ObjectはES 5/タイプとES 5/タイプの変換とテストを参照してください.新しく登場したES 6は6種類の原始タイプを含みます.Null Unidefined Number Boolean StringとSymbol、もう一つのObjectがあります.JavaScriptのデータタイプとデータ構造に詳しいです.新しく追加されたSymbolはすでに提出されています.具体的な概念はここではもう復唱しません.Symbolを参考にしてください.ES 6の普及のおかげで、クライアントブラウザも多くSymbolをサポートしています.例えば、Firefox v 36+とChrome v 38+など、ES 6サポート状況を具体的に参照してください.ES 6について深く知りたいなら、ES 6 In Depthという文章とES 6草案を見てもいいです.オブジェクト作成の特殊処理
let Ctor = function () {}; //
let baseCraate = function (prototype) {
if (!_.isObject(prototype)) {
return {};
}
// ,
if (nativeCreate) {
return nativeCreate(prototype);
}
// , 。
//
Ctor.prototype = prototype;
//
let result = new Ctor();
//
Ctor.prototype = null;
// Ctor
return result;
//
};
Object.creatのブラウザ間の互換性を処理するために、undersscoreは特殊な処理を行った.プロトタイプは直接的には実用化できませんので、まず空のオブジェクトを作成して、そのプロトタイプを私たちが実際化したいプロトタイプに指して、最後にそのオブジェクトの例に戻ります.コールバック処理
これを見る前に、void 0とはどういう意味ですか?引用文の由来はJavaScriptにあります.もしundefinedかどうかを判断したいなら、私たちは通常こう書きます.
if(a === undefined){}
しかし、JavaScriptのundefinedは信頼できません.このような関数を書いてみます.function test(a) {
var undefined = 1;
console.log(undefined); // => 1
if(a===undefined) {
// ...
}
}
識別子undefinedは本当に「未定義」を反映していないので、他の手段でこの意味を取得します.幸い、JavaScriptはまた、指定された表現に対して値を求め、信頼されたundefinedに戻るvoid演算子を提供しています.void expression
最も一般的な使い方は以下の演算でundefinedが得られ、式が0の場合の演算オーバヘッドが最小となります.void 0;
// or
void(0);
underscoreでは、undefinedを取得する必要があるところは、void 0によって代替されました.もちろん、曲線救国の方式は一つだけではないです.私達はjqueryを包むすぐ実行関数を見ました.(function(window,undefined) {
// ...
})(window)
この関数では、私たちは第二のパラメータ(形参の名前はundefined)を渡さないと、第二のパラメータの値は「未定義」に伝達されます.したがって、このようにして、関数の作用領域のすべてのundefinedは信頼されたundefinedであります. // underscore
// this (context ) argCount 、
let optimizeCb = function (func, context, argCount) {
if (context === void 0) {
return func;
}
// void 0 undefined,
switch (argCount) {
// argCount, argCount, null, 3,
// 1 ,
case 1: return function (value) {
return func.call(context, value);
};
// 2 , 2
// 3 , 、
// _.each、_.map
case 3:return function (value, index, collection) {
return func.call(context, value, index, collection)
};
// 4 , 、 、
//_.reduce、_reduceRight
case 4:return function (accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
// , apply
return function () {
return func.apply(context, arguments)
}
実は上のswitch-case文で直接に下記のreturn文を実行しなくてもいいです.同じ効果ではないです.callはappyよりずっと速いです.コールにはこれらのステップがありません.https://segmentfault.com/q/1010000007894513 http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.4.3http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.4.4次に、セット反復に対するコールバック処理である.
var builtinIteratee;
//
var cb = function(value, context, argCount) {
if (_.iteratee !== builtinIteratee) {return _.iteratee(value, context);}
// ,
if (value == null) {return _.identity;}
// value,
if (_.isFunction(value)) {return optimizeCb(value, context, argCount);}
// ,
if (_.isObject(value) && !_.isArray(value)) return _.matcher(value);
// ,
return _.property(value);
// ,
};
// , argCount cb 。 。
_.iteratee = builtinIteratee = function(value, context) {
return cb(value, context, Infinity);
};
残りの処理// 。
// , ,
let shallowProperty = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
};
// 。
// ES6 rest 。 。
let restArgs = function(func, startIndex) {
startIndex = startIndex == null ? func.length - 1 : +startIndex;
// startIndex null , 1, , startIndex
// rest
return function() {
// ,
let length = Math.max(arguments.length - startIndex, 0),
// length
rest = Array(length),
index = 0;
// 2 : func(a,b,*rest)
// : func(1,2,3,4,5); :func.call(this, 1,2, [3,4,5]);
for (; index < length; index++) {
rest[index] = arguments[index + startIndex];
}
// rest , , , rest ,
switch (startIndex) {
case 0: return func.call(this, rest);
// 0,
case 1: return func.call(this, arguments[0], rest);
// ,
case 2: return func.call(this, arguments[0], arguments[1], rest);
// 、
}
// , apply
let args = Array(startIndex + 1);
//
for (index = 0; index < startIndex; index++) {
args[index] = arguments[index];
}
//
args[startIndex] = rest;
return func.apply(this, args);
};
};
// 。
//
let MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
// +∞
let getLength = shallowProperty('length');
// length
let isArrayLike = function(collection) {
let length = getLength(collection);
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};