jQuery 的 each 方法
jQuery 有个 each 方法,是对于对象、数组通用的遍历方法。
具体的用法参考官方文档:.each()
今天我们也来实现这样一个 each 方法。
思路
参数:
参考 jQuery ,each 方法接收两个参数:
- 要遍历的对象;
- 要在其上执行的回调函数。
逻辑:
- 自然是要先判断其类型,是数组(类数组)就执行 for 循环(forEach 等不合适,后面再说),是对象就执行 for in 循环;
- 循环中执行回调函数。
关于数组、类数组的判断:
- 类数组是拥有一个 length 属性和 若干索引属性 的对象,常见的 arguments 对象就是类数组;
- 类数组不是数组, Array.prototype 上的方法无法在类数组对象上调用,会报错;
- 类数组的条件更“宽”,即符合数组特征的一定符合类数组特征,反之不一定,而它们的遍历方法一致。所以在数组、类数组通用的遍历方法 each 的判断逻辑中,可以只划一条“及格线”,只需要检测是否是类数组即可。
参考 JavaScript 权威指南中给出的方法:
function isArrayLike(o) {
if (o && // o is not null, undefined, etc
// o is an object
typeof o === "object" &&
// o.length is a finite number
isFinite(o.length) &&
// o.length is non-negative
o.length >= 0 &&
// o.length is an integer
o.length === Math.floor(o.length) &&
// o.length < 2^32
o.length < 4294967296) //数组的上限值
return true;
else
return false;
}
代码
基本款
由此,得到以下代码:
// 基本款
function each(obj, cb) {
var length, i = 0;
if ( isArrayLike(obj) ) {
length = obj.length;
for ( ; i < length; i++ ) {
// 此处如果用 forEach 遍历,注意参数的顺序
cb(i, obj[i])
}
} else {
for ( i in obj ) {
cb(i, obj[i])
}
}
return obj;
}
注: 此处直接用 forEach 遍历是可以的,但要注意 forEach 的回调函数的参数的顺序。
修复 this
遍历过程中,为了让回调函数中的 this 指向元素,我们使用 call() 方法:
// call() 方法第一个参数即为 this 指向的 context
callbackFunction.call(obj[i],i, obj[i])
代码:
// 修复 this
function each(obj, cb) {
var length, i = 0;
if ( isArrayLike(obj) ) {
length = obj.length;
for ( ; i < length; i++ ) {
// 使用 call()
cb.call(obj[i],i, obj[i])
}
} else {
for ( i in obj ) {
// 使用 call()
cb.call(obj[i],i, obj[i])
}
}
return obj;
}
终止遍历的功能
jQuery 的 each 方法有终止遍历的功能:
- 当回调函数返回值为 false,则终止遍历。
思路:
这个实现起来很简单,由于我们使用了 for 循环,可以在检测到 false 时,通过 break 轻松实现终止遍历。
if (callbackFunction.call(obj[i], i, obj[i]) === false) {
break;
}
用上面这段代码替换
callbackFunction.call(obj[i], i, obj[i])
最终代码:
// 最终代码
function each(obj, cb) {
var length, i = 0;
if ( isArrayLike(obj) ) {
length = obj.length;
for ( ; i < length; i++ ) {
// 终止遍历的功能
if (cb.call(obj[i], i, obj[i]) === false) {
break;
}
}
} else {
for ( i in obj ) {
// 终止遍历的功能
if (cb.call(obj[i], i, obj[i]) === false) {
break;
}
}
}
return obj;
}
测试
let obj = {
ak:"av",
bk:"bv"
}
let array = [1,2,3]
let arr = [{jb:'jb1'},{jw: 'jw1'}]
function logger (index, item) {
console.log(`~ ${index}: ${item} ~`);
}
each(obj, logger)
each(array, logger)
each(arr, logger)
输出:
~ ak: av ~
~ bk: bv ~
~ 0: 1 ~
~ 1: 2 ~
~ 2: 3 ~
~ 0: [object Object] ~
~ 1: [object Object] ~
成功~~
参考:
https://github.com/mqyqingfeng/Blog/issues/40
https://blog.csdn.net/beijiyang999/article/details/79760562
https://blog.csdn.net/beijiyang999/article/details/80179097