讀Zepto源碼之集合操做

接下來幾個篇章,都會解讀 zepto 中的跟 dom 相關的方法,也即源碼 $.fn 對象中的方法。javascript

讀Zepto源碼系列文章已經放到了github上,歡迎star: reading-zeptojava

源碼版本

本文閱讀的源碼爲 zepto1.2.0git

.forEach()

forEach: emptyArray.forEach

由於 zepto 的 dom 集合是類數組,因此這裏只是簡單地複製了數組的 forEach 方法。github

具體的 forEach 的用法見文檔:Array.prototype.forEach()segmentfault

.reduce()

reduce: emptyArray.reduce

簡單地複製了數組的 reduce 方法。數組

具體的 reduce 的用法見文檔:Array.prototype.reduce()微信

.push()

push: emptyArray.push

簡單地複製了數組的 push 方法。app

具體的 push 的用法見文檔:Array.prototype.push()dom

.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
},

zeptoeach 方法比較巧妙,在方法內部,調用的實際上是數組的 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 能夠傳遞兩個參數,selectorcontext ,即選擇器和上下文。

add 調用 $(selector, context) 來獲取符合條件的集合元素,這在上篇文章《讀Zepto源碼之神奇的$》已經有詳細的論述。

而後調用 concat 方法來合併兩個集合,用內部方法 uniq 來過濾掉重複的項,uniq 方法在《讀Zepto源碼以內部方法》已經有論述。最後也是返回一個 zepto 集合。

系列文章

  1. 讀Zepto源碼之代碼結構

  2. 讀 Zepto 源碼以內部方法

  3. 讀Zepto源碼之工具函數

  4. 讀Zepto源碼之神奇的$

參考

License

License: CC BY-NC-ND 4.0

最後,全部文章都會同步發送到微信公衆號上,歡迎關注,歡迎提意見:

做者:對角另外一面

相關文章
相關標籤/搜索