近來一直利用業餘時間在看jquery2.1.1原始碼,大約看了兩千行了。平時看的時候,做了一些筆記,貼出來分享。
1. Array.prototype.slice.call 可以將偽陣列轉化為真正的陣列
其實,這裡所謂的“偽陣列”就是有length屬性,並且有“0”、“1”、“2”等這些屬性的物件,如下程式碼:
var obj = { 0: "A", 1: "B", 2: "C", length: 3 }; var slice = [].slice; console.log(slice.call(obj));
這裡列印的結果就是一個真正的陣列:
另外,我們平時所寫的 $('div') ,其實也是這種偽陣列,可以看一下:
jquery原始碼中有一個方法是用來判斷是否是偽陣列的,其中就是根據物件是否有length屬性,並且物件的[length - 1]屬性有沒有值,來判斷的。這樣判斷會排除掉一個特殊的型別——String,string有length屬性,但是它的確不是偽陣列。
上面程式碼中,slice.call不僅能將偽陣列轉化成真正的陣列,還能想陣列的slice一樣,擷取元素。如下:
列印的結果可想而知:
2. window物件還有一個“window”屬性
jquery原始碼中,判斷一個物件是否是window的時候,用以下方法來判斷:
return obj.window === window;
用瀏覽器監測以下window物件的細節,會發現,window物件下確實還有一個window物件,而且是一個無限迴圈的結構。
3. 快捷方法
第一:
第二:
將一個物件強制轉換為與之對應的bool型別,可用: !!obj
相反,如果轉換成一直相反的bool型別,可用: !obj
4. === 與 ==
=== 是嚴格相等,不會進行型別轉換,而 == 是不嚴格相等,會進行型別轉換。有些js的書中,建議開發人員永遠不要用 == 或者 != 。
但是jquery原始碼中,有用到“==”或者“!=”的情況 —— 判斷 undefined 和 null 的時候。
5. 重寫了 toString()
有些物件型別重寫了 toString 方法,因此要獲取這個物件的名稱,就不能簡單的用 .toString() ,而是用 Object.prototype.toString.call
var a = [1, 2]; console.log(a.toString()); // 1,2 console.log(Object.prototype.toString.call(a)); // [Object Array]
6. Object( 'str' ) —— String強制型別轉換為Object
將一個字串強制型別轉換成object之後,將會返回一個標準的偽陣列物件。
Object( 'abc' ) --> String {0: "a", 1: "b", 2: "c", length: 3}
7. jQuery的each函式,最大的優點
each函式相比於for迴圈,最大的改進在於封閉了獨立的函式作用域。
先看一段for迴圈的程式碼:
console.log("current this", this); var $divs = $("div"), index = 0, length = $divs.length; for (; index < length; index++) { console.log(index, this); var j = 200; } console.log(j);
列印的結果如下:
列印結果可以看出:for迴圈裡面的語句塊,和外面的作用域相同;最可怕的是 for 迴圈裡面定義的變數,在外面可以識別。 別傷心,這就是js的一個“特點”。
為了解決這個問題,我們再看看each函式的程式碼:
console.log("current this", this); var $divs = $("div"); $divs.each(function (index, elem) { console.log(index, this); var x = 100; }); console.log(x);
列印結果如下:
很容易看出,each函式中的作用域,和外部作用域不同,而且each函式中定義的變數完全是區域性變數,外面不可獲取。這正式我們想要的!
另外,大家還肯能會發現,each比較類似與 for ... in 。 for...in 是迭代器模式,比 for(i=0;i<length;i++)要方便很多。但是除了上面提到了作用域之外,each和for...in就完全一樣了嗎? 當然不是!
以上兩段程式碼,結果卻大相徑庭。為何? 因為 for...in 會遍歷一個物件的隱式原型元素,而 each 則像for(i=0;i<length;i++)一樣中規中矩。
8. call和apply的引數傳遞不同
他倆的傳參方式不同可能大家都知道,說一個具體的例子吧,jquery中用到的。
var arr = [5, 6, [1, 2], [3, 4]]; console.log(Array.prototype.concat.call([], arr)); // [5, 6, [1, 2], [3, 4]] console.log(Array.prototype.concat.apply([], arr)); // [5, 6, 1, 2, 3, 4]
以上程式碼,輸出的結果完全不一樣。看明白這一點,才能說明你真正理解了兩者傳參的不同。
---------------------------------------------------------------
以上是本次全部內容。jquery還會繼續往下看,筆記也會繼續整理。再有新內容,再分享。