Prototype源码浅析 Enumerable部分(二)(2)


function any(iterator, context) {
iterator = iterator || Prototype.K;
var result = false;
this.each(function(value, index) {
if (result = !!iterator.call(context, value, index))
throw $break;
});
return result;
}


include:判断 Enumerable 中是否存在指定的对象,基于 == 操作符进行比较  这个方法有一步优化,就是调用了indexOf方法,对于数组来说,indexOf返回-1就不可以知道相应元素不存在了,如果集合没有indexOf方法,就只能查找比对了。这里的查找和没有任何算法,一个个遍历而已,如果要改写也容易,不过平时应用不多,因此估计也没有花这个精力去优化这个。所以如果结果为true的时候效率比结果为false的时候要高一些,看运气了。

复制代码 代码如下:


function include(object) {
if (Object.isFunction(this.indexOf))//这个判定函数应该很熟悉了
if (this.indexOf(object) != -1) return true;//有indexOf就直接调用

var found = false;
this.each(function(value) {//这里的效率问题
if (value == object) {
found = true;
throw $break;
}
});
return found;
}



下面是一组过滤数据的方法:返回单个元素:max | min | detect返回一个数组:grep | findAll | reject | partition 其中max和min并不局限于数字的比较,字符的比较一样可以。max(iterator, context)依旧可以带有两个参数,可以先用iterator处理之后再来比较值,这样的好处就是不必局限于特定的数据类型,比如,对象数组按照一定规则取最大值:

复制代码 代码如下:


console.dir([{value : 3},{value : 1},{value : 2}].max(function(item){
return item.value;
}));//3


因此源码的实现方式可以想象,直接比较的时候,实现方式可以如下:

复制代码 代码如下:


function max() {
var result;
this.each(function(value) {
if (result == null || value >= result) //result==null是第一次比较
result = value;
});
return result;
}


扩展之后,value要进一步变为value = (iterator处理后的返回值):

复制代码 代码如下:


function max(iterator, context) {
iterator = iterator || Prototype.K;
var result;
this.each(function(value, index) {
value = iterator.call(context, value, index);
if (result == null || value >= result)
result = value;
});
return result;
}


min的原理也一样。detect和any的原理和接近,any是找到一个true就返回true,detect是找到一个true就返回满足true条件的那个值。源码就不贴了。grep 这个很眼熟啊,一个unix/linux工具,其作用也很眼熟——就是返回所有和指定的正则表达式匹配的元素。只不过unix/linux只能处理字符串,这里扩展了范围,但是基本形式还是没有变。如果集合的每一项都是字符串,那么实现起来回事这样:

复制代码 代码如下:


Enumerable.grep = function(filter) {
if(typeof filter == 'string'){
filter = new RegExp(filter);
}
var results = [];
this.each(function(value,index){
if(value.match(filter)){
results.push(value);
}
})
return results;
};


但是有一现在要处理的集合可能并都是字符串,为了达到更广泛的应用,首先要考虑的就是调用形式。看上面的实现,注意这么一句:
if(value.match(filter))
其中value是个字符串,match是String的方法,现在要扩展所支持的类型,要么给每一个value都加上match方法,要么转换形式。显然第一种巨响太大,作者转换了思路:
if (filter.match(value))
这么一来,不论value为何值,只要filter有对应的match方法即可,上面对于RegExp对象,是没有match方法的,于是在源码中,作者扩展了RegExp对象:
RegExp.prototype.match = RegExp.prototype.test;
注意上面的match和String的match有本质区别。这么一来,如果value是对象,我们的filter只需要提供相应的检测对象的match方法即可。于是就有:

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdjdzy.html