接下來幾個篇章,都會解讀 zepto 中的跟 相關的方法,也即源碼 對象中的方法。 讀Zepto源碼系列文章已經放到了github上,歡迎star: "reading zepto" 源碼版本 本文閱讀的源碼為 "zepto1.2.0" .forEach() 因為 zepto 的 集合是類數組,所以這 ...
接下來幾個篇章,都會解讀 zepto 中的跟 dom
相關的方法,也即源碼 $.fn
對象中的方法。
讀Zepto源碼系列文章已經放到了github上,歡迎star: reading-zepto
源碼版本
本文閱讀的源碼為 zepto1.2.0
.forEach()
forEach: emptyArray.forEach
因為 zepto 的 dom
集合是類數組,所以這裡只是簡單地複製了數組的 forEach
方法。
具體的 forEach
的用法見文檔:Array.prototype.forEach()
.reduce()
reduce: emptyArray.reduce
簡單地複製了數組的 reduce
方法。
具體的 reduce
的用法見文檔:Array.prototype.reduce()
.push()
push: emptyArray.push
簡單地複製了數組的 push
方法。
具體的 push
的用法見文檔:Array.prototype.push()
.sort()
sort: emptyArray.sort
簡單地複製了數組的 sort
方法。
具體的 sort
的用法見文檔:Array.prototype.sort()
.splice()
splice: emptyArray.splice
簡單地複製了數組的 splice
方法。
具體的 splice
的用法見文檔:Array.prototype.splice()
.indexOf()
indexOf: emptyArray.indexOf
簡單地複製了數組的 indexOf
方法。
具體的 indexOf
的用法見文檔:Array.prototype.indexOf()
.get()
get: function(idx) {
return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
},
這個方法用來獲取指定索引值的元素。
不傳參(idx === undefined
)時,不傳參調用數組的 slice
方法,將集合中的所有元素返回。
當傳遞的參數大於或等於零(idx
)時,返回相應索引值的元素 this[idx]
,如果為負數,則倒數返回this.[idx + this.length]
。
例如 $('li').get(-1)
返回的是倒數第1個元素,也即最後一個元素
.toArray()
toArray: function() { return this.get() }
toArray
方法是將元素的類數組變成純數組。toArray
內部不傳參調用 get
方法,上面已經分析了,當不傳參數時,get
方法調用的是數組方法 slice
, 返回的自然就是純數組了。
.size()
size: function() {
return this.length
}
size
方法返回的是集合中的 length
屬性,也即集合中元素的個數。
.concat()
concat: function() {
var i, value, args = []
for (i = 0; i < arguments.length; i++) {
value = arguments[i]
args[i] = zepto.isZ(value) ? value.toArray() : value
}
return concat.apply(zepto.isZ(this) ? this.toArray() : this, args)
},
數組中也有對應的 concat
方法,為什麼不能像上面的方法那樣直接調用呢?
這是因為 $.fn
其實是一個類數組對象,並不是真正的數組,如果直接調用 concat
會直接把整個 $.fn
當成數組的一個 item
合併到數組中。
for (i = 0; i < arguments.length; i++) {
value = arguments[i]
args[i] = zepto.isZ(value) ? value.toArray() : value
}
這段是對每個參數進行判斷,如果參數是 zepto
的集合(zepto.isZ(value)
),就先調用 toArray
方法,轉換成純數組。
return concat.apply(zepto.isZ(this) ? this.toArray() : this, args)
這段同樣對 this
進行了判斷,如果為 zepto
集合,也先轉換成數組。所以調用 concat
後返回的是純數組,不再是 zepto
集合。
.map()
map: function(fn) {
return $($.map(this, function(el, i) { return fn.call(el, i, el) }))
}
map
方法的內部調用的是 zepto
的工具函數 $.map
,這在之前已經在《讀Zepto源碼之工具函數》做過了分析。
return fn.call(el, i, el)
map
方法對回調也做了包裝,call
的第一個參數為 el
,因此可以在 map
的回調中通過 this
來拿到每個元素。
map
方法對 $.map
返回的數組調用了 $()
方法,將返回的數組再次包裝成 zepto
對象,因此調用 map
方法後得到的數組,同樣具有 zepto
集合中的方法。
.slice()
slice: function() {
return $(slice.apply(this, arguments))
}
slice
同樣沒有直接用數組的原生方法,也像 map
方法一樣,將返回的數組再次包裝成 zepto
對象。
.each()
each: function(callback) {
emptyArray.every.call(this, function(el, idx) {
return callback.call(el, idx, el) !== false
})
return this
},
zepto
的 each
方法比較巧妙,在方法內部,調用的其實是數組的 every
方法,every
遇到 false
時就會中止遍歷,zepto
也正是利用 every
這種特性,讓 each
方法也具有了中止遍歷的能力,當 callback
返回的值為布爾值 false
時,中止遍歷,註意這裡用了 !==
,因為 callback
如果沒有返回值時,得到的值會是 undefined
,這種情況是需要排除的。
同樣,each
的回調中也是可以用 this
拿到每個元素的。
註意,each
方法最後返回的是 this
, 所以在 each
調用完後,還可以繼續調用 集合中的其他方法,這就是 zepto
的鏈式調用,這個跟 map
方法中返回 zepto
集合的原理差不多,只不過 each
返回的是跟原來一樣的集合,map
方法返回的是映射後的集合。
.add()
add: function(selector, context) {
return $(uniq(this.concat($(selector, context))))
}
add
可以傳遞兩個參數,selector
和 context
,即選擇器和上下文。
add
調用 $(selector, context)
來獲取符合條件的集合元素,這在上篇文章《讀Zepto源碼之神奇的$》已經有詳細的論述。
然後調用 concat
方法來合併兩個集合,用內部方法 uniq
來過濾掉重覆的項,uniq
方法在《讀Zepto源碼之內部方法》已經有論述。最後也是返回一個 zepto
集合。
系列文章
參考
- Array.prototype.forEach()
- Array.prototype.reduce()
- Array.prototype.push()
- Array.prototype.sort()
- Array.prototype.splice()
- Array.prototype.indexOf()
License
作者:對角另一面