這篇文章將要告訴你:
- 什么是類(lèi)數(shù)組對(duì)象
- 類(lèi)數(shù)組對(duì)象是如何出現(xiàn)的
- 如何避免使用類(lèi)數(shù)組對(duì)象的常見(jiàn)問(wèn)題
- 將類(lèi)數(shù)組對(duì)象轉(zhuǎn)換為普通對(duì)象的方法
類(lèi)數(shù)組對(duì)象
類(lèi)數(shù)組(Array-like Object)對(duì)象是 javascript 中比較冷門(mén)的內(nèi)容斧蜕,如果不了解的話双霍,會(huì)被坑到。
類(lèi)數(shù)組對(duì)象 foo 有以下兩個(gè)陷阱:
- 有 foo.length 屬性批销,卻沒(méi)有 foo.push() 方法
- 和 for-in 一起使用會(huì)有坑
類(lèi)數(shù)組對(duì)象的主要使用/產(chǎn)生場(chǎng)景有以下兩種:
- 函數(shù)參數(shù) arguments
- querySelectorAll 的結(jié)果
下面來(lái)分別說(shuō)一下洒闸。
1. 類(lèi)數(shù)組對(duì)象——函數(shù)參數(shù)arguments
function a(){
console.log(arguments); //----------------1. 函數(shù)的傳入?yún)?shù),類(lèi)數(shù)組對(duì)象
console.log(arguments.length); //---------2. 傳入?yún)?shù)的個(gè)數(shù)
console.log(arguments.callee); //---------3. 指向函數(shù)本身 a()
console.log(Object.prototype.toString.call(arguments)); //----4. 精確判斷對(duì)象類(lèi)型
}
a(1,2,'aa');
執(zhí)行結(jié)果是:
- [1, 2, "aa", callee: function, Symbol(Symbol.iterator): function]
- 3
- function a(){……(整個(gè)函數(shù)均芽,此處省略)
- [object Arguments]
從執(zhí)行結(jié)果可以看出丘逸,arguments的長(zhǎng)度是傳入?yún)?shù)的個(gè)數(shù),但它還包括callee這個(gè)屬性掀宋,指向自身深纲。callee可以用于遞歸,比如在a()內(nèi)可以繼續(xù)通過(guò)調(diào)用arguments.callee(3,4,5)
實(shí)現(xiàn)遞歸劲妙。
2. 類(lèi)數(shù)組對(duì)象——querySelectorAll的結(jié)果
類(lèi)數(shù)組對(duì)象應(yīng)該使用var i = 0; i < a.length;i++
方式遍歷湃鹊,和for-in一起使用的時(shí)候就是個(gè)災(zāi)難啊。
下面我們來(lái)看一下災(zāi)難現(xiàn)場(chǎng):我們有三個(gè)DOM:
<p class="cls-p">第一段</p>
<p class="cls-p">第二段</p>
<p class="cls-p">第三段</p>
然后我們使用querySelectorAll進(jìn)行選擇镣奋,使用for-in遍歷:
var doms = document.querySelectorAll('.cls-p');
console.log(doms.length); // 3
for (var i in doms) {
console.log(i); // 打印doms中屬性的key
}
for-in 的打印結(jié)果真是令人目瞪口呆:
原理是這樣的余赢,for-in 遍歷的是元素的所有屬性掸驱,包括原型鏈中的屬性,所以會(huì)打印出keys, entries 這種原型鏈的屬性没佑。
console.log( 'keys' in doms) // true,'keys' 是 doms的屬性
console.log(doms.hasOwnProperty('keys')) // false温赔,‘keys’ 不是doms的自有屬性
在上面的代碼中蛤奢,我們用了hasOwnProperty()
,這個(gè)方法用于判斷當(dāng)前屬性是否是對(duì)象的自有屬性陶贼。
那么我們可以用hasOwnProperty()
來(lái)填平for-in
的坑么啤贩?這是可以的。
for (var i in doms) {
if (doms.hasOwnProperty(i)) {
console.log(i); //打印doms中自有屬性的key
}
};
當(dāng)然拜秧,最好的辦法就是:
- 使用for循環(huán)來(lái)遍歷類(lèi)數(shù)組對(duì)象
- 使用for循環(huán)來(lái)遍歷類(lèi)數(shù)組對(duì)象
- 使用for循環(huán)來(lái)遍歷類(lèi)數(shù)組對(duì)象
將類(lèi)數(shù)組對(duì)象轉(zhuǎn)換為普通對(duì)象
文章前面提到過(guò)痹屹,類(lèi)數(shù)組對(duì)象有 foo.length 屬性,卻沒(méi)有 foo.push() 方法枉氮。通過(guò)將類(lèi)數(shù)組對(duì)象轉(zhuǎn)換為普通對(duì)象志衍,可以使用push()方法。
方法一:for 循環(huán)復(fù)制到新對(duì)象中
function objToArr() {
// arguments.push[4];
// 如果運(yùn)行上面的代碼聊替,會(huì)報(bào)錯(cuò) "Uncaught TypeError: Cannot read property '4' of undefined"
var arr = [];
for (var i = 0, len = arguments.length; i < len; i++)
arr[i] = arguments[i];
return arr;
}
var arr = objToArr(1, 2, 3);
arr.push(4);
console.log(arr); // [1,2,3,4]楼肪,符合預(yù)期
方法二:使用Array.prototype.slice方法
原理:slice() 不修改原數(shù)組,只會(huì)返回一個(gè)淺復(fù)制了原數(shù)組中的元素的一個(gè)新數(shù)組惹悄。
function objToArr() {
// arguments.push[4];
// 如果運(yùn)行上面的代碼春叫,會(huì)報(bào)錯(cuò) "Uncaught TypeError: Cannot read property '4' of undefined"
var arr = Array.prototype.slice.call(arguments);
return arr;
}
var arr = objToArr(1, 2, 3);
arr.push(4);
console.log(arr); // [1,2,3,4],符合預(yù)期
參考文章: