前端如何優雅處理類數組對象?

1、背景介紹

Leo 部門最近來了位前端實習生 Robin,做爲師傅,Leo 認真的爲 Robin 介紹了公司業務、部門工做等狀況,還有前端的新人學習地圖。javascript

接下來 Robin 開始一週愉快的學習啦~html

一週後,Leo 爲 Robin 同窗佈置了學習做業,開發一個【人員搜索選擇】的頁面,效果大體以下:前端

Robin 看完這個效果圖後,一臉得意的樣子,這確實不難呀~java

過幾天后,Robin 帶着本身寫的代碼,給 Leo 展現了她的代碼,並疑惑的問到:git

她將這個「數組」輸出到控制檯:github

Leo 看了看代碼:數組

getUserList(){
   const memberList = $('#MemberList li');
   memberList.map(item => { console.log(item) });
   console.log(memberList);
}

Leo 又問到:app

Robin 一臉疑惑,而後 Leo 再原來代碼上,加了個 Array.from 方法以下:dom

getUserList(){
    const memberList = Array.from($('#MemberList li'));
    memberList.map(item => {
        console.log(item)
    })
    console.log(memberList)
}

而後從新執行代碼,輸出下面結果:函數

Leo 輸出的結果,跟 Robin 說到:

Robin 滿臉期待望着師傅,對類數組對象更加充滿期待。

2、類數組對象介紹

2.1 概念介紹

所謂 類數組對象,即格式與數組結構相似,擁有 length 屬性,能夠經過索引來訪問或設置裏面的元素,可是不能使用數組的方法,就能夠歸類爲類數組對象

舉個例子🌰:

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

2.2 常見類數組對象

  • arguments 對象;
function f() {
  return arguments;
}
f(1,2,3)

// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  • NodeList(好比 document.getElementsByClassName('a') 獲得的結果;
document.getElementsByTagName('img')
// HTMLCollection(3) [img, img, img]
  • typedArray(好比 Int32Array);

typedArray 即 類型化數組對象 是一種相似數組的對象,它提供了一種用於訪問原始二進制數據的機制。JavaScript引擎會作一些內部優化,以便對數組的操做能夠很快。然而,隨着Web應用程序變得愈來愈強大,尤爲一些新增長的功能例如:音頻視頻編輯,訪問WebSockets的原始數據等,很明顯有些時候若是使用JavaScript代碼能夠快速方便地經過類型化數組來操做原始的二進制數據將會很是有幫助。 —— 《MDN 類型化數組》

const typedArray = new Uint8Array([1, 2, 3, 4])
// Uint8Array(4) [1, 2, 3, 4]

另外使用 jQuery 獲取元素,會被 jQuery 作特殊處理成爲 init 類型:

$('img')
// init(3) [img, img, img, prevObject: init(1), context: document, selector: "img"]

固然還有一些不常見的類數組對象,好比「Storage API 返回的結果」,這裏就不一一列出。

3、類數組對象屬性

下面經過 Robin 代碼做爲示例,介紹類數組對象的屬性:

const memberList = $('#MemberList li');

3.1 讀寫

// 讀取
memberList[0];
// Node: <li>...</li>

// 寫入
memberList[0] = document.createElement("div")
memberList[0];
//  Node: <div>...</div>

3.2 長度

memberList.length; 
// 10

3.3 遍歷

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

/*
    Node: <li>...</li>
    Node: <li>...</li>
  ... 共10個,省略其餘
*/

memberList.map(item => console.log(item));

/*
    0
  ... 共10個,省略其餘
*/

但若是是 HTMLCollection 就不能使用 map 咯:

const img = document.getElementsByTagName("img");
img.map(item => console.log(item));

// Uncaught TypeError: img.map is not a function

4、類數組對象處理

Leo 看了看 Robin 處理這個列表的代碼:

getUserList(){
    const memberList = $('#MemberList li');
    const result = {
        text: [],
        dom : [],
    };
    memberList.map(item => {
        item = memberList[item]
        // 判斷當前節點是否有 checked 類名
    })
    console.log(result)
    this.showToast(`選中成員:${result.text}`);
}

很明顯,Robin 並無對 jQuery 獲取到的 memberList 作處理,直接使用,經過索引來獲取對應值。
Leo 繼續和 Robin 介紹到:

4.1 Array.from

使用 Array.from 來將類數組對象轉爲數組對象,操做起來很是簡單:

getUserList(){
    const memberList = Array.from($('#MemberList li'));
    // 省略其餘代碼
}

語法以下:

Array.from(arrayLike[, mapFn[, thisArg]])

參數

  1. arrayLike 想要轉換成數組的僞數組對象或可迭代對象。
  2. mapFn 可選若是指定了該參數,新數組中的每一個元素會執行該回調函數。
  3. thisArg 可選可選參數,執行回調函數 mapFnthis 對象。

返回值
一個新的數組實例。

更多 Array.from 介紹能夠查看文檔。

4.2 Array.prototype.slice.call()

slice() 方法返回一個新的數組對象,這一對象是一個由 beginend 決定的原數組的淺拷貝(包括 begin,不包括end)。原始數組不會被改變

實現代碼:

getUserList(){
    const memberList = Array.prototype.slice.call($('#MemberList li'));
    // 省略其餘代碼
}

更多 Array.prototype.slice 介紹能夠查看文檔。

4.3 ES6展開運算符

展開語法(Spread syntax), 能夠在函數調用/數組構造時, 將數組表達式或者string在語法層面展開;還能夠在構造字面量對象時, 將對象表達式按key-value的方式展開。

實現代碼:

getUserList(){
    const memberList = [...document.getElementsByTagName("li")];
    // 省略其餘代碼
}

更多 ES6展開運算符 介紹能夠查看文檔。

4.4 利用concat+apply

getUserList(){
    const memberList = Array.prototype.concat.apply([], $('#MemberList li'));
    // 省略其餘代碼
}

5、案例小結

Leo 介紹完這些知識後,Robin 又優化了下本身的代碼,涉及到類數組對象操做的核心 js 代碼以下:

class SelectMember {
    constructor(){
        this.MockUsers = window.MockUsers;
        this.init();
    }
    init(){
        this.initMemberList('#MemberList', this.MockUsers);
        this.initBindEvent();
    }
      // ... 省略部分代碼,保留核心代碼
    submitSelect(){
        const memberList = Array.from($('#MemberList li'));
        const result = {
            text: [],
            dom : [],
        };
        memberList.map(item => {
            const hasClass = $(item).children('.round-checkbox').children('span').hasClass(this.selectClassName);
            if(hasClass){
                result.text.push($(item).children('.user-data').children('h4').text());
                result.dom.push(item);
            }
        })
        this.showToast(`選中成員:${result.text}`);
    }
}

let newMember = new SelectMember();

很明顯,使用正確方式來處理類數組對象,不只能使咱們代碼更加少,減小轉換處理,還能提升代碼質量。

整個項目的完整代碼,能夠在個人 github 查看

https://github.com/pingan8787/Leo-JavaScript/blob/master/Cute-Demo/10.Learn-Array-Liked-Objects/index.html

6、總結

本文咱們經過一個實際場景,詳細介紹了類數組對象在實際開發中的使用,對於常見的類數組對象,咱們還介紹了處理方式,能很大程度減小咱們處理類數組對象的操做,將類數組統一轉成數組,更加方便對數據的操做。但願看完本文的你,之後再遇到類數組對象,不會再一臉懵逼咯~~~

相關文章
相關標籤/搜索