介绍
jq 有一个 each 方法,是一个通用遍历方法。可用于遍历对象和数组。
语法
jQuery.each(object, [callback]);
callback 有两个参数:第一个是对象的属性名或者是数组的索引,第二个为对应的值。
// 数组
$.each( [0,1,2], function(i, n){
console.log( "Item #" + i + ": " + n );
});
// Item #0: 0
// Item #1: 1
// Item #2: 2
// 对象
$.each({ name: "John", lang: "JS" }, function(i, n) {
console.log("Name: " + i + ", Value: " + n);
});
// "Name: name, Value: John"
// "Name: lang, Value: JS"
ES5 提供的 forEach 方法不能跳出循环,但 jq 的 each 方法可以。
$.each( [0, 1, 2, 3, 4, 5], function(i, n){
if (i > 2) return false;
console.log( "Item #" + i + ": " + n );
});
// Item #0: 0
// Item #1: 1
// Item #2: 2
实现 each
根据参数类型的不同选择不用的循环语句,数组就调用 for 循环,对象就调用 for in 循环。对于类数组对象也选择 for 循环。
可以利用在 《javascript 类型判断(plainObject …》中讲到的 isArrayLike 方法。
function each(obj, callback) {
let length, i = 0;
// 类数组对象就使用 for 循环
if (isArrayLike(obj)) {
length = obj.length;
for (; i < length; i++) {
callback(i, obj[i]);
}
} else {
// 对象使用 for in 循环
for (i in obj) {
if (obj.hasOwnProperty(i)) {
callback(i, obj[i]);
}
}
}
return obj;
}
支持终止循环
把
callback(i, obj[i])
替换成
if (callback(i, obj[i]) === false) break;
支持 this,能够指向当前遍历的元素。
例子
// 我们给每个人添加一个 age 属性,age 的值为 18 + index
var person = [
{name: 'kevin'},
{name: 'daisy'}
]
$.each(person, function(index, item){
this.age = 18 + index;
})
把
if (callback(i, obj[i]) === false) break;
替换为
if(callback.call(obj[i], i, obj[i]) === false) break;
最终代码
function each(obj, callback) {
let length, i = 0;
// 类数组对象就使用 for 循环
if (isArrayLike(obj)) {
length = obj.length;
for (; i < length; i++) {
if(callback.call(obj[i], i, obj[i]) === false) break;
}
} else {
// 对象使用 for in 循环
for (i in obj) {
if (obj.hasOwnProperty(i)) {
if(callback.call(obj[i], i, obj[i]) === false) break;
}
}
}
return obj;
}
性能比较
const arr = Array.from({length: 1000000}, (v, i) => i);
console.time("for");
let i = 0, valueOne = 0;
for (; i < arr.length; i++) {
valueOne += arr[i];
}
console.timeEnd("for");
console.time("each");
let valueTwo = 0;
each(arr, function (index, item) {
valueTwo += item;
});
console.timeEnd("each");
结果
我们都知道 each 也是使用 for 循环,但为什么时间会差这么多了?它们的唯一区别是有没有使用 call 方法,可见 call 方法是造成性能损失的原因。
参考:
[1] JavaScript专题之jQuery通用遍历方法each的实现
[2] forEach
[3] for in