后面的代碼真是越看越難理解,經常需要結合內部/接口函數一起,所以采用跳讀的方式解析,基本按照模塊由易到難的順序解析。
~~~
456 _.initial = function(array, n, guard) {
return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
};
~~~
這個guard參數說是保證默認返回第一個值,不過我看了很久覺得意義不大,猜測可能是以前的接口。這里的`slice = Array.prototype.slice`。這里有兩個地方比較好,一是用Array的原型函數來處理array參數,這樣可以避免判斷array是否數組,二是用max來避免超出數組長度。
~~~
671 _.range = function(start, stop, step) {
if (arguments.length <= 1) {
stop = start || 0;
start = 0;
}
step = step || 1;
var length = Math.max(Math.ceil((stop - start) / step), 0);
var range = Array(length);
for (var idx = 0; idx < length; idx++, start += step) {
range[idx] = start;
}
return range;
};
~~~
這個函數本什沒有什么特別的,只不過我在調用的時候將step賦值為小數,就出現了javascript著名的精度問題。網上應該有不少的解決方案,這里提供一種目前我在項目中用到的解決方法:將數字轉為字符串在去小數點之后轉為整數進行計算,計算完成后轉字符串加上小數點再轉成小數,舉個例子
~~~
1.11 ==> "1.11" ==> "111" ==> 111
2.2 ==> "2.2" ==> "220" ==> 220
111+220 ==> 331 ==> "331" ==> "3.31" ==> 3.31
~~~
數組代碼看得累了,從后面的看起吧~
~~~
1269 _.noConflict = function() {
root._ = previousUnderscore;
return this;
};
~~~
這個讓渡函數其實原理比較簡單,就是初始化underscore前?`previousUnderscore=window._`對原有對象進行儲存,如果需要讓渡避免沖突,則進行還原同時返回當前underscore對象。再來看看JQuery的實現原理:
~~~
noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
}
~~~
剛開始看的時候犯2了,函數可以用`===`來比較?不是只能比較簡單的數據對象?呵呵,其實這個是通過引用地址來判斷的,因為之前初始化的時候`window.$=JQuery`所以$會指向JQuery的地址,所以可以這樣判斷。后面一個if考慮到JQuery這個變量名也被占用的時候,也進行讓渡,最后返回JQuery對象。可能是考慮多版本的情況吧~
~~~
1487 _.mixin = function(obj) {
_.each(_.functions(obj), function(name) {
var func = _[name] = obj[name];
_.prototype[name] = function() {
var args = [this._wrapped];
push.apply(args, arguments);
return result(this, func.apply(_, args));
};
});
};
// Add all of the Underscore functions to the wrapper object.
_.mixin(_);
~~~
這個用于擴展underscore自身的接口函數,通過循環遍歷對象來淺拷貝對象屬性。這里考慮到函數的實例化,所以一方面將函數作為內部函數使用,同時擴展到prototype屬性上。考慮得比較周全。
~~~
1469 _.chain = function(obj) {
var instance = _(obj);
instance._chain = true;
return instance;
};
~~~
這個函數讓underscore支持鏈式調用,鏈式調用寫起來很美觀,但是調試略顯不方便。結合之前的代碼來看,underscore實現鏈式調用的基本原理是:將參數緩存在內部屬性_wrapped中,調用函數時傳入該屬性值,執行后返回當前this指針。直到執行value函數時返回_wraped中的值。