jQuery提供了通用遍历方法each,同时现在很多浏览器都支持原生的foreach方法,出现这些方法的有什么背景呢?
背景
因为很多时候我们需要遍历数组和对象,如果是数组,就调用 for 循环,如果是对象,就使用 for in 循环
,有一个例外是类数组对象,对于类数组对象,我们依然可以使用 for 循环。因此我们就在想有没有一个通用的方法即可以遍历数组也可以遍历对象呢?答案是肯定的!
each介绍
jQuery 的 each 方法,作为一个通用遍历方法,可用于遍历对象和数组。
jQuery.each(object, [callback])
回调函数拥有两个参数:第一个为对象的成员或数组的索引,第二个为对应变量或内容。
退出循环
尽管 ES5 提供了 forEach 方法,但是 forEach 没有办法中止或者跳出 forEach 循环,除了抛出一个异常。但是对于 jQuery 的 each 函数,如果需要退出 each 循环可使回调函数返回 false,其它返回值将被忽略。
具体实现
基本实现:要根据参数的类型进行判断,如果是数组,就调用 for 循环,如果是对象,就使用 for in 循环,有一个例外是类数组对象,对于类数组对象,我们依然可以使用 for 循环。
function each(obj, callback) { var length, i = 0; if ( isArrayLike(obj) ) { length = obj.length; for ( ; i < length; i++ ) { callback(i, obj[i]) } } else { for ( i in obj ) { callback(i, obj[i]) } } return obj; }
实现终止循环 按照 jQuery each 的实现,当回调函数返回 false 的时候,我们就中止循环。
callback(i, obj[i]) //替换成 if (callback(i, obj[i]) === false) { break; }
this 我们在实际的开发中,我们有时会在 callback 函数中用到 this。
if (callback(i, obj[i]) === false) { break; } // 替换成 if (callback.call(obj[i], i, obj[i]) === false) { break; }
最终代码
function each(obj, callback) { var length, i = 0; if (isArrayLike(obj)) { length = obj.length; for (; i < length; i++) { if (callback.call(obj[i], i, obj[i]) === false) { break; } } } else { for (i in obj) { if (callback.call(obj[i], i, obj[i]) === false) { break; } } } return obj; }
性能比较
使用console.time()
和console.timeEnd()
比较for和each的性能,for 循环的性能是明显好于 each 函数的,each 函数本质上也是用的 for 循环,到底是慢在了哪里呢?
猜测会不会是call的原因呢,编写each 函数和 eachWithCall 函数,唯一的区别就是 eachWithCall 调用了 call,从结果我们可以推测出,call 会导致性能损失
,但也正是 call 的存在,我们才能将 this 指向循环中当前的元素。因此有舍有得吧。