接下来几个篇章,都会解读 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
集合。
最后,全部文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
做者:对角另外一面