underscore.js源碼解析(一)

一直想針對一個框架的源碼好好的學習一下編程思想和技巧,提升一下本身的水平,可是看過一些框架的源碼,都感受看的莫名其妙,看不太懂,最後找到這個underscore.js因爲這個比較簡短,一千多行,並且讀起來容易一些,因此就決定是它了,那廢話很少說開始咱們的源碼學習。node

underscore.js源碼GitHub地址: https://github.com/jashkenas/underscore/blob/master/underscore.js
 
本文解析的underscore.js版本是1.8.3
 

結構解析

 
咱們先從總體的結構開始分析(其中加入了註釋加以解釋說明)
 
  1 (function() {
  2   // 建立一個root對象,在瀏覽器中表示爲window(self)對象,在Node.js中表示global對象,
  3   // 之因此用用self代替window是爲了支持Web Worker
  4   var root = typeof self == 'object' && self.self === self && self ||
  5             typeof global == 'object' && global.global === global && global ||
  6             this;
  7   // 保存"_"(下劃線變量)被覆蓋以前的值
  8   var previousUnderscore = root._;
  9   // 原型賦值,便於壓縮
 10   var ArrayProto = Array.prototype, ObjProto = Object.prototype;
 11   // 將內置對象原型中的經常使用方法賦值給引用變量,以便更方便的引用
 12   var push = ArrayProto.push,
 13       slice = ArrayProto.slice,
 14       toString = ObjProto.toString,
 15       hasOwnProperty = ObjProto.hasOwnProperty;
 16   // 定義了一些ECMAScript 5方法
 17   var nativeIsArray = Array.isArray,
 18       nativeKeys = Object.keys,
 19       nativeCreate = Object.create;
 20   //跟神馬裸函數有關,我也不清楚什麼意思,有知道能夠告訴我
 21   var Ctor = function(){};
 22   // 建立一個下劃線對象
 23   var _ = function(obj) {
 24     // 若是在"_"的原型鏈上(即_的prototype所指向的對象是否跟obj是同一個對象,要知足"==="的關係)
 25     if (obj instanceof _) return obj;
 26     // 若是不是,則構造一個
 27     if (!(this instanceof _)) return new _(obj);
 28     // 將underscore對象存放在_.wrapped屬性中
 29     this._wrapped = obj;
 30   };
 31   // 針對不一樣的宿主環境, 將Undersocre的命名變量存放到不一樣的對象中
 32   if (typeof exports != 'undefined' && !exports.nodeType) {//Node.js
 33     if (typeof module != 'undefined' && !module.nodeType && module.exports) {
 34       exports = module.exports = _;
 35     }
 36     exports._ = _;
 37   } else {//瀏覽器
 38     root._ = _;
 39   }
 40   //版本號
 41   _.VERSION = '1.8.3';
 42   //下面是各類方法之後的文章中會具體說明
 43   .
 44   .
 45   .
 46   .
 47   .
 48   .
 49   // 建立一個chain函數,用來支持鏈式調用
 50   _.chain = function(obj) {
 51     var instance = _(obj);
 52     //是否使用鏈式操做
 53     instance._chain = true;
 54     return instance;
 55   };
 56   // 返回_.chain裏是否調用的結果, 若是爲true, 則返回一個被包裝的Underscore對象, 不然返回對象自己
 57   var chainResult = function(instance, obj) {
 58     return instance._chain ? _(obj).chain() : obj;
 59   };
 60   // 用於擴展underscore自身的接口函數
 61   _.mixin = function(obj) {
 62     //經過循環遍歷對象來淺拷貝對象屬性
 63     _.each(_.functions(obj), function(name) {
 64       var func = _[name] = obj[name];
 65       _.prototype[name] = function() {
 66         var args = [this._wrapped];
 67         push.apply(args, arguments);
 68         return chainResult(this, func.apply(_, args));
 69       };
 70     });
 71   };
 72   _.mixin(_);
 73   // 將Array.prototype中的相關方法添加到Underscore對象中, 這樣Underscore對象也能夠直接調用Array.prototype中的方法
 74   _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
 75     //方法引用
 76     var method = ArrayProto[name];
 77     _.prototype[name] = function() {
 78       // 賦給obj引用變量方便調用
 79       var obj = this._wrapped;
 80       // 調用Array對應的方法
 81       method.apply(obj, arguments);
 82       if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
 83       //支持鏈式操做
 84       return chainResult(this, obj);
 85     };
 86   });
 87 
 88   // 同上,而且支持鏈式操做
 89   _.each(['concat', 'join', 'slice'], function(name) {
 90     var method = ArrayProto[name];
 91     _.prototype[name] = function() {
 92       //返回Array對象或者封裝後的Array
 93       return chainResult(this, method.apply(this._wrapped, arguments));
 94     };
 95   });
 96   //返回存放在_wrapped屬性中的underscore對象
 97   _.prototype.value = function() {
 98     return this._wrapped;
 99   };
100 
101   // 提供一些方法方便其餘狀況使用
102   _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
103   _.prototype.toString = function() {
104     return '' + this._wrapped;
105   };
106 
107   // 對AMD支持的一些處理
108   if (typeof define == 'function' && define.amd) {
109     define('underscore', [], function() {
110       return _;
111     });
112   }
113 }());

總結

具體分析在上面源碼中的註釋裏寫的已經很詳細了,下面再從頭理順一下總體的結構:
 
首先underscore包裹在一個匿名自執行的函數當中
內部定義了一個"_"變量
將underscore中的相關方法添加到_原型中,建立的_對象就具有了underscore方法
將Array.prototype中的相關方法添加到Underscore對象中, 這樣Underscore對象也能夠直接調用Array.prototype中的方法

以後的文章中,我會針對underscore中的方法進行具體解析,感謝你們的觀看,也但願可以和你們互相交流學習,有什麼分析的不對的地方歡迎你們批評指出

相關文章
相關標籤/搜索