【Zepto源码】集合方法(一)

老姚
老姚 发布于 7 天前 浏览:624 类型:原创 - 随笔 分类:JavaScript - zepto源码分析系列 二维码: 作者原创 版权保护
不管zepto对象,还是jquery对象,其本质上都是一个类数组对象。
什么是类数组对象呢,网上有很多资料,我也专门写过《文章》
具体来说就是有length属性,可以按下标来访问。

本文从这个角度来分析一些zepto实例方法。

#size
既然是类数组,有length属性,看此集合的大小。
其实现应该说是最简单的:
$.fn.size = function() {
        return this.length;
};
其中$.fn,应该没人不知道吧,
$是个函数,$.fn是$.prototype。

#toArray
把$实例变成真正数组。
可以以如下的方式实现:
$.fn.toArray = function() {
        return [].slice.call(this);
};
当然了其源码不是这么做的,内部调用了get方法:
$.fn.toArray = function() {
        return this.get();
};

#get
我们可以使用$('div')[0]获取第一个元素,那么也可以使用$('div').get(0)来做。
其实现如下:
$.fn.get = function(idx) {
        return idx === undefined ? [].slice.call(this) : this[idx >= 0 ? idx : idx + this.length];
};
如果没传参数,那么返回整个数组,也就相当于调用toArray。
其中参数idx,可以是负数,比如$('div').get(-2),表示获取倒数第二个div元素。

#first
获取第一个元素,其实现竟然没用通过get来做,
其实现如下:
$.fn.first = function() {
        var el = this[0];
        return el && !isObject(el) ? el :$(el);
};
取出第一个元素后,要判断是否不是对象,如果不是的话,返回的是$实例。
比如$([{x:1},2,3]).first(),返回的不是{x:1},而是$({x:1}),进而可以继续调用其他方法。
好奇怪的设计,理由个人不清楚。

#last
类似first,取出最后一个:
$.fn.last = function() {
        var el = this[this.length - 1];
        return el && isObject(el) ? el : $(el);
};

#push
因为数组有个push方法,其直接借用了:
$.fn.push = [].push;

#sort
直接借用数组的:
$.fn.sort = [].sort;

#splice
直接借用数组的:
$.fn.splice = [].splice;

#indexOf
直接借用数组的:
$.fn.indexOf = [].indexOf;

#slice
但是slice,如果简单直接借用数组的,那么返回的是个数组。
而zepto需要返回的$实例对象。因此借用后,还要封装成zepto实例:
$.fn.slice = function() {
        return $([].slice.apply(this, arguments));
};

#forEach
数组对象本身就有forEach方法,那么直接借用其即可:
$.fn.forEach = [].forEach;

#each
each接口与forEach接口不一样,在之前的文章还专门吐槽过。。
实现如下:
$.fn.each = function(callback) {
        [].every.call(this, function(el, idx) {
                return callback.call(el, idx, el) !== false;
        });
        return this;
};
借用数组的every的方法,每次调用回调后,看其结果返回值是否false?
这样可以实现类似break的效果。
最后返回this,支持链式调用。

#map
实现如下:
$.fn.map = function(fn) {
        return $($.map(this, function(el, i) {
                return fn.call(el, i, el);
        }));
};
其调用了工具方法map,这样首先返回的是数组对象,可以参考$.map的实现,
而实例map方法要求返回的是$实例对象的,而不是数组对象。

#reduce
直接借用数组的:
$.fn.reduce = [].reduce;

#eq
有人经常把eq和get搞混。
eq返回的$实例,而get是其中dom元素。
其实现如下:
$.fn.eq = function(idx) {
        return idx === -1 ? this.slice(idx) : this.slice(idx, +idx + 1);
};
这个跟slice有关,从上面知道slice调用了数组的slice,
比如[1, 2, 3].slice(-1),得到是[3],
而[1, 2, 3].slice(-1, 0),是空数组,
要得到最后一个只能使用[1, 2, 3].slice(-1),
而其他是正常的,比如得到倒数第二个:
[1, 2, 3].slice(-2, -1),是[2]。

#concat
zepto对象合并方法。返回的结果仍然是数组:
$.fn.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);
};

其中zepto.isZ用来判断是否是$实例。
遍历所有参数,如果本身是zepto实例,那么就转化成数组,再添加到数组args中。
然后借用数组的concat方法。
注意后面的zepto.isZ(this) ? this.toArray() : this
原因可能$.fn.concat也可能被其他函数借用,而不是作为实例方法调用。例如源码中的内部方法:
function flatten(array) {
        return array.length > 0 ? $.fn.concat.apply([], array) : array;
}

#pluck
pluck这个英文单词的意思是“采、摘”的意思。
比如$('div').pluck('id'),会得到由id组成的数组。
prototype.js中有此api,而一般函数式库中也有类似的api,比如underscore.js。
实现用$.map即可:
$.fn.pluck = function(property) {
        return $.map(this, function(el) {
                return el[property];
        });
};

#总结
上面的这些方法,是集合的通用常见方法。
比如数组有个filter,为啥没分析呢?(后续会分析的)
$.fn.filter的参数selector,跟数组不一样的。所以没有放在本文。

本文完。
z
给个赞 15 人点赞
收藏 14 人收藏
评论 已有 2 条评论;以下用户言论只代表其个人观点,不代表 前端网(QDFuns) 的观点或立场。
登录 以后才能发表评论
最新评论
老姚
老姚7 天前2F
节奏狗 //@极乐网:沙发!我是大哥!楼下的二弟呢?
举报 支持 (0) 回复 (0)
极乐网
极乐网7 天前1F
沙发!我是大哥!楼下的二弟呢?
举报 支持 (0) 回复 (1)
老姚 老姚 作者

与自己为敌,与自己为友,一边深挖思想,一边埋葬自己。

作者最新