接下來幾個篇章,都會解讀 zepto 中的跟 dom
相關的方法,也即源碼 $.fn
對象中的方法。javascript
讀Zepto源碼系列文章已經放到了github上,歡迎star: reading-zeptojava
本文閱讀的源碼爲 zepto1.2.0git
forEach: emptyArray.forEach
由於 zepto 的 dom
集合是類數組,因此這裏只是簡單地複製了數組的 forEach
方法。github
具體的 forEach
的用法見文檔:Array.prototype.forEach()segmentfault
reduce: emptyArray.reduce
簡單地複製了數組的 reduce
方法。數組
具體的 reduce
的用法見文檔:Array.prototype.reduce()微信
push: emptyArray.push
簡單地複製了數組的 push
方法。app
具體的 push
的用法見文檔:Array.prototype.push()dom
sort: emptyArray.sort
簡單地複製了數組的 sort
方法。函數
具體的 sort
的用法見文檔:Array.prototype.sort()
splice: emptyArray.splice
簡單地複製了數組的 splice
方法。
具體的 splice
的用法見文檔:Array.prototype.splice()
indexOf: emptyArray.indexOf
簡單地複製了數組的 indexOf
方法。
具體的 indexOf
的用法見文檔:Array.prototype.indexOf()
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: function() { return this.get() }
toArray
方法是將元素的類數組變成純數組。toArray
內部不傳參調用 get
方法,上面已經分析了,當不傳參數時,get
方法調用的是數組方法 slice
, 返回的天然就是純數組了。
size: function() { return this.length }
size
方法返回的是集合中的 length
屬性,也即集合中元素的個數。
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: 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: function() { return $(slice.apply(this, arguments)) }
slice
一樣沒有直接用數組的原生方法,也像 map
方法同樣,將返回的數組再次包裝成 zepto
對象。
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: function(selector, context) { return $(uniq(this.concat($(selector, context)))) }
add
能夠傳遞兩個參數,selector
和 context
,即選擇器和上下文。
add
調用 $(selector, context)
來獲取符合條件的集合元素,這在上篇文章《讀Zepto源碼之神奇的$》已經有詳細的論述。
而後調用 concat
方法來合併兩個集合,用內部方法 uniq
來過濾掉重複的項,uniq
方法在《讀Zepto源碼以內部方法》已經有論述。最後也是返回一個 zepto
集合。
最後,全部文章都會同步發送到微信公衆號上,歡迎關注,歡迎提意見:
做者:對角另外一面