1. 程式人生 > >ES6-遍歷陣列

ES6-遍歷陣列

陣列是一種很重要的資料結構。那麼我們如何遍歷陣列呢?
我們如何遍歷陣列中的元素?20年前JavaScript剛萌生時,你可能這樣實現陣列遍歷:

for (var index = 0; index < myArray.length; index++) {
  console.log(myArray[index]);
}

自ES5正式釋出後,你可以使用內建的forEach方法來遍歷陣列:

myArray.forEach(function (value,index) {
console.log(index+":"+value);
});

這段程式碼看起來更加簡潔,但這種方法也有一個小缺陷:你不能使用break語句中斷迴圈,也不能使用return語句返回到外層函式。另外,forEach方法是Array物件的方法,所以對於DOM的類陣列,如NodeList物件,則不能遍歷。

當然,如果只用for迴圈的語法來遍歷陣列元素也很不錯。
那麼,你一定想嘗試一下for-in迴圈:

for (var index in myArray) { // 千萬別這樣做
  console.log(myArray[index]);
}

這絕對是一個糟糕的選擇,為什麼呢?

  • 在這段程式碼中,賦給index的值不是實際的數字,而是字串“0”、“1”、“2”,此時很可能在無意之間進行字串算數計算,例如:“2” + 1 == “21”,這給編碼過程帶來極大的不便。
  • 作用於陣列的for-in迴圈體除了遍歷陣列元素外,還會遍歷自定義屬性。舉個例子,如果你的陣列中有一個可列舉屬性myArray.name,迴圈將額外執行一次,遍歷到名為“name”的索引。就連陣列原型鏈上的屬性都能被訪問到。
  • 最讓人震驚的是,在某些情況下,這段程式碼可能按照隨機順序遍歷陣列元素
  • 簡而言之,for-in是為普通物件設計的,你可以遍歷得到字串型別的鍵,因此不適用於陣列遍歷

強大的for-of迴圈

每個具有遍歷器方法的物件都稱為”可遍歷”物件。
for of遍歷一種資料集合時,首先會尋找這個集合是否有遍歷器方法,沒有就丟擲錯誤,有就呼叫這個方法。遍歷器方法返回一個遍歷物件,遍歷物件的根本特徵就是具有next方法。每次呼叫next方法,都會返回一個代表當前成員的資訊物件,具有value和done兩個屬性。

for of就是不斷呼叫next方法來遍歷的
ES6規定,遍歷器方法儲存在物件的[Symbol.iterator]屬性中(這個屬性的名字是內建的Symbol值,防止重名)

let obj = {
    a:1,
    b:2
};
console.log(obj[Symbol.iterator]); //undefined
for(let x of obj){
    console.log(x);   
}
// Uncaught TypeError: obj is not iterable

物件沒有預設的iterator介面([Symbol.iterator]),所以用for of遍歷時就丟擲了錯誤。
我們來給這個物件定義一個[Symbol.iterator]屬性。

obj[Symbol.iterator]=function(){
    return {
        next: function(){
            return { value:1, done:false }
        }
    };
}
for(let x of obj){
    console.log(x);
}

有了遍歷器方法後,for of就能遍歷這個物件了,不過done屬性為false,這個遍歷就永遠不會結束,它會一直列印1。

物件(Object)之所以沒有預設部署Iterator介面,是因為物件的哪個屬性先遍歷,哪個屬性後遍歷是不確定的,需要開發者手動指定。本質上,遍歷器是一種線性處理,對於任何非線性的資料結構,部署遍歷器介面,就等於部署一種線性轉換。不過,嚴格地說,物件部署遍歷器介面並不是很必要,因為這時物件實際上被當作Map結構使用,ES5沒有Map結構,而ES6原生提供了。

具有[Symbol.iterator]屬性的物件有:陣列、某些類似陣列的物件、Set和Map結構。我們可以自己定義物件的[Symbol.iterator]屬性來覆蓋預設的[Symbol.iterator]屬性

let arr=[1,2,3];
arr[Symbol.iterator]=function(){
    let index=0;
    return {
        next:function(){
            if(index<arr.length){
                index++;
                return {
                    value:1,
                    done:false  
                }
            }else{
                return {
                    value:"遍歷結束",
                    done:true
                }
            }
        }
    }
};
 //模擬for of迴圈
let iterator = arr[Symbol.iterator]();
iterator.next();    // {value: 1, done: false}
iterator.next();    // {value: 1, done: false}  
iterator.next();    // {value: 1, done: false}
iterator.next();    // {value: "遍歷結束", done: true}

for(let x of arr){
    console.log(x);  // 1 1 1
}

ES6陣列遍歷方法

ES6給陣列原型添加了幾種新的遍歷陣列方法:Array.prototype.entries() Array.prototype.keys()和Array.prototype.values()(瀏覽器支援不好)

for…of迴圈內部呼叫的是資料結構的Symbol.iterator方法來遍歷。
Array.prototype.entries() Array.prototype.keys()和Array.prototype.values()這些方法返回一個新的Symbol.iterator方法,for of內部呼叫的就是新迭代物件

Array.prototype.entries()
作用:遍歷陣列的鍵值對
引數:無
返回值:返回一個新的Array Iterator物件,該物件包含陣列中每個索引的鍵/值對

var arr = ["a", "b", "c"];
var iterator = arr.entries();
console.log(iterator);  // Array Iterator {}
console.log(iterator.next());   // {value: [0, "a"], done:false}
console.log(iterator.next()); // {value: [0, "a"], done:false}
console.log(iterator.next()); // {value: [0, "a"], done:false}

var iterator2 = arr.keys();
console.log(iterator);  // Array Iterator {}
console.log(iterator.next());   // {value: 0, done: false}
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
//陣列預設的遍歷器物件
for(let x of arr[Symbol.iterator]()){
        console.log(x);
}

// for of呼叫arr.keys()返回的遍歷物件
for(let x of arr.keys()){
    console.log(x);
}

// for of呼叫arr.entries()返回的遍歷物件
for(let [index,value] of arr.entries()){
    console.log(index,value);
}

console.log(arr.keys()===arr.entries());  //false

arr.entries()返回新的遍歷物件,它包含了陣列每個索引的鍵值對
arr.keys()返回新的遍歷物件,它包含陣列中每個索引的鍵


擴充套件運算子(…)也可以將某些資料結構轉為陣列。
[...[1,2,3]]    //[1,2,3]
[...document.querySelectorAll('div')] // NodeList物件轉換為Array例項

擴充套件運算子背後呼叫的是遍歷器介面(Symbol.iterator),如果一個物件沒有部署這個介面,就無法轉換。擴充套件運算子呼叫物件的遍歷器方法,進行遍歷。

let arr2=['a','b','c'];
var iterator=arr2.entries();
console.log([...iterator]);

圖片