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