1.什么是偽數(shù)組?
偽數(shù)組(ArrayLike)又稱(chēng)類(lèi)數(shù)組,雖然從名字上來(lái)看,貌似和數(shù)組很像,但實(shí)際上和數(shù)組有很大區(qū)別:
- 偽數(shù)組是一個(gè)對(duì)象,所以
偽數(shù)組 instanceof Array===false 和 偽數(shù)組 instanceof Object===true 這兩個(gè)等式都成立 - 偽數(shù)組必須含有l(wèi)ength屬性,且必須是 number 類(lèi)型,否則就不叫偽數(shù)組,就是一個(gè)普通對(duì)象而已
- 如果length不為0,那么必須要有數(shù)值型下標(biāo)(即0或者'0'都可以,只要可以通過(guò)Number()轉(zhuǎn)換為數(shù)值即可)存儲(chǔ)的數(shù)據(jù)
- 偽數(shù)組不能調(diào)用數(shù)組原型上的方法。就是:xx.push()、xx.slice()、xx.indexOf() 等等這些方法都不能用
了解了偽數(shù)組的特點(diǎn)后,我們可以根據(jù)其特點(diǎn)舉幾個(gè)例子
2.舉個(gè)栗子
不是偽數(shù)組
var a = {};
var b = { length: 3 };
是偽數(shù)組
var c = { length: 0 };
var d = { 0: '888', length: 1 };
var e = { 1: 'abc', length: 3 }
var f = { '0': 'abc',1:'test', length: 3 }
var g = { 0: 'abc',2:'test', length: 1 }
我們打印下上面7個(gè)變量的結(jié)果如下:

3.偽數(shù)組轉(zhuǎn)數(shù)組
- 方法一:
Array.prototype.slice.call(arrayLike)或者Array.prototype.slice.apply(arrayLike)。
我們知道數(shù)組的slice方法可以對(duì)數(shù)組進(jìn)行切割(不傳參,返回原數(shù)組),返回新數(shù)組。由于類(lèi)數(shù)組并沒(méi)有數(shù)組的這些方法,所以通過(guò)前面在javascript中的this指向講解過(guò)call的原理,我們可以借用方法。所以上面代碼的call函數(shù)原理是:
arrayLike.fn1=this //this指向slice
arrayLike.fn1() //即arrayLike調(diào)用fn1也就是slice方法,所以slice方法中的this指向arrayLike。所以偽數(shù)組被切割成數(shù)組返回出來(lái)
Array.prototype上的方法原本只能用來(lái)操作array對(duì)象。但用call apply 可以把任意對(duì)象當(dāng)做this傳入某個(gè)方法,如此一來(lái),方法中用到的this的地方就不再局限于原來(lái)規(guī)定的對(duì)象,而是得到更廣的適用性。
- 方法二:
Array.prototype.splice.call(arrayLike, 0)或者Array.prototype.splice.call(arrayLike, 0)
splice也是數(shù)組的方法,對(duì)數(shù)組進(jìn)行切割(第一個(gè)參數(shù)為切割起始位置,必填),我就不介紹了。和上面原理一樣。
- 方法三:
Array.prototype.concat.apply([], arrayLike)
- 方法四:使用es6自帶的
Array.from(arrayLike)方法
4.使用上面轉(zhuǎn)換方法測(cè)試
上面我們舉了幾個(gè)偽數(shù)組的例子以及如何將偽數(shù)組轉(zhuǎn)換為數(shù)組,現(xiàn)在我們對(duì)這些例子進(jìn)行測(cè)試:
1.使用 Array.prototype.slice.call(arrayLike)
注:splice我就不舉列子,和slice一樣。
var translate=function(arrayLike){
return Array.prototype.slice.call(arrayLike)
}
console.log(translate(c),translate(c)[0],translate(c).length);
console.log(translate(d),translate(d)[0],translate(d).length);
console.log(translate(e),translate(e)[0],translate(e).length);
console.log(translate(f),translate(f)[2],translate(f).length);
console.log(translate(g),translate(g)[1],translate(g).length);
運(yùn)行結(jié)果如下:

2.使用 Array.prototype.concat.apply([], arrayLike) 方法
var translate=function(arrayLike){
return Array.prototype.concat.apply([], arrayLike)
}
console.log(translate(c),translate(c)[0],translate(c).length);
console.log(translate(d),translate(d)[0],translate(d).length);
console.log(translate(e),translate(e)[0],translate(e).length);
console.log(translate(f),translate(f)[2],translate(f).length);
console.log(translate(g),translate(g)[1],translate(g).length);
運(yùn)行結(jié)果如下:

3.使用 Array.from(arrayLike) 方法
var translate=function(arrayLike){
return Array.from(arrayLike)
}
console.log(translate(c),translate(c)[0],translate(c).length);
console.log(translate(d),translate(d)[0],translate(d).length);
console.log(translate(e),translate(e)[0],translate(e).length);
console.log(translate(f),translate(f)[2],translate(f).length);
console.log(translate(g),translate(g)[1],translate(g).length);
運(yùn)行結(jié)果如下:

5.對(duì)比
上面測(cè)試結(jié)果:
- 從打印表面上看,
Array.prototype.concat.apply([], arrayLike)和Array.from(arrayLike)所有輸出結(jié)果都一樣,而Array.prototype.slice.call(arrayLike)結(jié)果有些許差別 - 如果類(lèi)數(shù)組length值和所含數(shù)據(jù)個(gè)數(shù)相等,三個(gè)方法結(jié)果都一樣
- 如果類(lèi)數(shù)組length值大于所含數(shù)據(jù)個(gè)數(shù),
slice將所缺失的用empty來(lái)補(bǔ)充,contact和from用undefined來(lái)補(bǔ)充。但是打印缺失的都為undefined,所以三者只是從形式上有區(qū)別,使用沒(méi)什么區(qū)別 - 如果類(lèi)數(shù)組length值小于所含數(shù)據(jù)個(gè)數(shù),三個(gè)方法都會(huì)將多余的裁減掉。
6.常見(jiàn)的類(lèi)數(shù)組對(duì)象
1.arguments對(duì)象
arguments對(duì)象是所有(非箭頭)函數(shù)中都可用的局部變量。你可以使用arguments對(duì)象在函數(shù)中引用函數(shù)的參數(shù)。arguments對(duì)象不是一個(gè)Array。它類(lèi)似于Array,但除了length屬性和索引元素之外沒(méi)有任何Array屬性。例如,它沒(méi)有pop方法。但它可以被轉(zhuǎn)換為一個(gè)真正的Array。
function foo(a, b, c) {
console.log(arguments);
}
foo(1, 2, 3);
打印結(jié)果如下:

2.jquery對(duì)象
//html
<p>1</p>
<p>2</p>
<p>3</p>
//js
console.log($('p'))

3.js獲取dom節(jié)點(diǎn)的方法,如getElementById等
//html
<p>1</p>
<p>2</p>
<p>3</p>
//js
console.log('通過(guò)querySelectorAll:',document.querySelectorAll("p"))
console.log('通過(guò)getElementsByTagName:',document.getElementsByTagName("p"))
