很早就想研究underscore源碼了,雖然underscore.js這個庫有些過期了,可是我仍是想學習一下庫的架構,函數式編程以及經常使用方法的編寫這些方面的內容,又剛好沒什麼其它要研究的了,因此就告終研究underscore源碼這一心願吧。html
underscore.js源碼研究(1)
underscore.js源碼研究(2)
underscore.js源碼研究(3)
underscore.js源碼研究(4)
underscore.js源碼研究(5)
underscore.js源碼研究(6)
underscore.js源碼研究(7)
underscore.js源碼研究(8)git
參考資料:underscore.js官方註釋,undersercore 源碼分析,undersercore 源碼分析 segmentfault編程
咱們知道,_既是underscore的函數也是對象,咱們把方法先掛載到它的對象屬性上,使得方法能夠直接調用,而後咱們利用mixin方法把這些方法掛載到它的原型屬性上,使得這個函數返回的underscore對象能夠利用這些方法。segmentfault
那麼若是其它庫也用到了_這個符號呢?underscore中是這樣解決的:api
var previousUnderscore = root._; _.noConflict = function() { root._ = previousUnderscore; return this; }; //給underscore從新定義一個符號: var __ = _.noConflict();
underscore這個庫裏面有一些私有的變量和方法,也會暴露出一些方法,這些暴露出的方法一旦被用戶改寫,可能整個庫就不能按照但願的方向運行了。因此underscore把一些暴露的方法賦給一些內建方法,而後在其它方法使用這些方法的時候能夠用內建方法判斷是否被改寫了。示例以下:緩存
//聲明內建方法 var builtinIteratee; //雙重賦值賦給內建方法 _.iteratee = builtinIteratee = function(value, context) { return cb(value, context, Infinity); }; //cb函數中判斷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) && !_.isArray(value)) return _.matcher(value); return _.property(value); };
值得一提的是,因爲js中傳遞的是引用,因此賦給內建方法並不會有太大的內存開銷,因此我以爲這個想法很是好。架構
new Person()實際上爲咱們作了以下事情:app
//建立一個對象,並設置其指向的原型 var obj = {'__proto__': Person.prototype}; //調用Person()的構造方法,而且將上下文(this)綁定到obj上 Person.apply(obj, arguments); //返回建立的對象 return obj;
可是使用new須要一個構造函數,這在不少時候很是不方便。更多時候,咱們但願經過一個對象直接建立另外一個對象,因而就有了Object.create()方法。Object.create(obj)的原理是這樣的:ide
//建立一個臨時的構造函數,並將原型指向 var Ctor = function() {}; ctor.prototype = obj; //經過new新建一個對象 var obj2 = new Ctor(); //清除Ctor,防止內存泄漏。並返回obj2 Ctor.prototype = null; return obj2;
因此,mdn上這樣描述Object.create()方法:建立一個新對象,使用現有的對象來提供新建立的對象的__proto__。函數式編程
須要注意的是,爲了提高速度,underscore把Ctor進行了緩存:
var Ctor = function() {};
因此後面當咱們爲了防止內存泄漏清除Ctor的時候,只是清除它的原型。
而underscore的baseCreate方法就是對Object.create()方法的polyfill:
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; };
須要注意的是,Object.create()方法支持多個參數,可是underscore的baseCreate方法只支持一個參數。