【前端幫幫忙】第10期 淺析類數組對象

什麼是類數組對象

簡單來講,和數組相似,擁有length屬性,能夠經過索引來訪問或設置裏面的元素,可是不能使用數組的方法。javascript

看個例子:html

arr[0];
// => "dazhi"
複製代碼

這裏的arr必定是一個數組嗎?不必定,也多是一個對象。前端

let arr = {
    0: 'dazhi'
}
console.log(arr[0]); // dazhi
複製代碼

再來看個例子:java

let arr = ['name', 'age', 'job'];

// 建立一個類數組對象
let arrLike = {
    0: 'name',
    1: 'age',
    2: 'job',
    length: 3
}
複製代碼

注意:這邊arrLike必須加上length屬性,否則它就是一個普通對象而已。git

爲何叫作類數組對象呢?咱們從讀寫、獲取長度、遍歷這三個方面來看看這兩個對象。github

讀寫

console.log(arr[0]); // name
console.log(arrLike[0]); // name

arr[0] = 'new name';
arrLike[0] = 'new name';

console.log(arr[0]); // new name
console.log(arrLike[0]); // new name
複製代碼

獲取長度

console.log(arr.length); // 3
console.log(arrLike.length); // 3
複製代碼

遍歷

for (let i = 0;i < arr.length; i++){
    console.log(arr[i]);
}

// name 
// age 
// job

for (let i = 0;i < arrLike.length; i++){
    console.log(arrLike[i]);
}
// name 
// age 
// job
複製代碼

有沒有很像?當咱們使用使用數組的方法呢?繼續往下看:數組

arr.push('gender');

arrLike.push('gender');  // 報錯
複製代碼

原形畢露了,終歸是類數組。app

那若是類數組就想用數組的方法呢?能夠把類數組轉換爲數組。函數

轉換爲數組

Array.prototype.slice.call()

var arrLike2 = Array.prototype.slice.call(arrLike);
arrLike2.push('gender');
console.log(arrLike2[3]); // gender
複製代碼

Array.from()

var arrLike3 = Array.from(arrLike);
arrLike3.push('gender');
console.log(arrLike3[3]); // gender
複製代碼

Array.prototype.splice.call()

var arrLike4 = Array.prototype.splice.call(arrLike, 0);

arrLike4.push('gender');

console.log(arrLike4[3]); // gender
複製代碼

注意

若是length值和實際元素不相等呢?學習

let arrLike = {
    0: 'name',
    1: 'age',
    length: 3
}
console.log(Array.from(arrLike)); // ["name", "age", undefined]
複製代碼

能夠看到,若是length值大於實際元素的數量,不足的將用undefined填充。

若是反過來呢?

let arrLike = {
    0: 'name',
    1: 'age',
    length: 1
}
console.log(Array.from(arrLike)); // ["name"]
複製代碼

最終只保留了一個元素。可見,length值是決定最終生成數組的長度的,多餘的去掉,不足的用undefined填充。

那若是咱們索引不從0和1開始,能夠嗎?

let arrLike = {
    2: 'name',
    3: 'age',
    length: 2
}
console.log(Array.from(arrLike));  // [undefined, undefined]
複製代碼

可見,0和1是有用的,會影響到最終的填充索引。

類數組對象的應用

說了這麼多,類數組能用來作什麼?

還記得arguments對象嗎?它就是一個類數組對象。咱們看下MDN上對其的描述:

Arguments對象

arguments對象是全部(非箭頭)函數中均可用的局部變量。你可使用arguments對象在函數中引用函數的參數。arguments對象不是一個Array。它相似於Array,但除了length屬性和索引元素以外沒有任何Array屬性。例如,它沒有pop方法。但它能夠被轉換爲一個真正的Array

MDN地址:developer.mozilla.org/zh-CN/docs/…

看個例子:

function foo(a, b, c) {
    console.log(arguments);
}

foo(1, 2, 3);
複製代碼

控制檯看下打印結果:

咱們能夠經過arguments對象在函數內部引用傳遞進來的參數:

function foo(a, b, c) {
    console.log(arguments[0]);
    console.log(arguments[1]);
    console.log(arguments[2]);
}

foo(1, 2, 3);
// 1
// 2
// 3
複製代碼

1.length屬性

argumentslength屬性表明的是實參的個數,由於咱們調用函數的時候,有時候並非全部參數都須要傳入,看下面的代碼:

function foo(a, b, c) {
    console.log('實參的個數:' + arguments.length); // 1
}

foo(1);

console.log('形參的個數爲:' + foo.length); // 3
複製代碼

2.auguments和對應參數的綁定

function foo(a, b, c, d) {
    // "use strict";
    console.log(a, arguments[0]); // 1 1
    
    // 改變形參
    a = 11;
    
    console.log(a, arguments[0]); // 11 11
    
    // 改變arguments
    arguments[1] = 22;
    
    console.log(b, arguments[1]); // 22 22
    
    // 未傳入的參數
    console.log(c); // undefined
    
    c = 3;
    
    console.log(c, arguments[2]); // 3 undefined
    
    arguments[3] = 4;
    console.log(d, arguments[3]); // undefined 4
}

foo(1, 2);
複製代碼

總結:

  1. 有傳入的參數,實參和arguments的值會共享,沒有傳入的參數,不會共享
  2. 在嚴格模式下,不管參數有沒有傳入,實參和arguments的值都不會共享

3.傳遞參數

將參數從一個函數傳遞到另外一個函數。

function foo() {
    bar.apply(this, arguments);
}

function bar(a, b, c) {
    console.log(a, b, c);
}

foo(1, 2, 3);

// 1 2 3
複製代碼

4.arguments轉爲數組

arguments除了能夠用上面的幾個轉爲數組的方法,還可使用...展開運算符。

function bar(a, b) {
  // 用...把argumens轉爲數組
  console.log([...arguments]); // [1, 2]
}

bar(1, 2);
複製代碼

可是若是應用到普通的類數組對象呢?

let arrLike5 = {
    a: 1,
    b: 2,
    length: 2
}

console.log([...arrLike5]);  // 報錯 Uncaught TypeError: arrLike5 is not iterable
複製代碼

報錯的意思是:arrLike5不是可迭代的,也就證明了arguments除了是類數組對象,仍是一個可迭代對象,而咱們自定義的對象並不具有可迭代功能,因此不能使用展開運算符。

由於咱們自定義的類數組對象不具有可迭代功能,因此也沒辦法使用for...of來遍歷:

let arrLike = {
  0: 'name',
  1: 'age',
  2: 'job',
  length: 3
}

for (let arrItem of arrLike) {
  console.log(arrItem);
}

// 一樣會報錯 Uncaught TypeError: arrLike is not iterable
複製代碼

那麼forEachfor...in呢?

forEach是數組的方法,天然也沒辦法使用。

來看下for...in

let arrLike = {
  0: 'name',
  1: 'age',
  2: 'job',
  length: 3
}

for (let index in arrLike) {
  console.log(index);
}

// 0
// 1
// 2
// length
複製代碼

for...in是遍歷對象的可枚舉屬性,會把length也遍歷出來。

因此只有for循環能夠正確遍歷類數組對象。

另外,arguments的應用其實還有不少,這裏就不繼續展開了,你們有興趣能夠本身再去找資料學習一下,好比:

  1. 參數不定長
  2. 函數柯里化
  3. 遞歸調用
  4. 函數重載
  5. ...

其餘類數組對象

咱們在頁面上隨便寫幾個p標籤:

<p></p>
<p></p>
<p></p>
複製代碼

而後用document.getElementsByTagName()獲取:

var ps = document.getElementsByTagName('p');
console.log(ps);
複製代碼

能夠看到,裏面也有length屬性,可是它並非一個數組,咱們能夠來檢測一下:

// 類數組對象不能使用數組的方法
ps.push('a');  // 報錯:Uncaught TypeError: ps.push is not a function

console.log(Object.prototype.toString.call(ps)); // [object HTMLCollection]

console.log(Object.prototype.toString.call([])); // [object Array]
複製代碼

好了,本文就先到這裏了。

最後

感謝您的閱讀,但願對你有所幫助。因爲本人水平有限,若是文中有描述不當的地方,煩請指正,很是感謝。

關注

歡迎你們關注個人公衆號前端幫幫忙,一塊兒交流學習,共同進步!

參考:

github.com/mqyqingfeng…

相關文章
相關標籤/搜索