ES6新特性之迭代器與for-of循環

我們知道遍歷數組的方式之一就是 使用for循環來遍歷,如:

var arr = [1, 2, 3, 4, 5, 6];
for (var i = 0; i < arr.length; i++) {
    console.log(arr[i]); //1,2,3,4,5,6
}

但是這樣感覺代碼有點多,不簡潔,因此ES5發佈之後,可以使用數組的forEach()迭代方法來遍歷數組:

forEach()方法:爲數組的第一項給定函數,對數組的第一項運行給定的函數,該函數沒有返回值。相當於遍歷數組。

var arr = [1, 2, 3, 4, 5, 6];

arr.forEach(function (value) {
    console.log(value); //1,2,3,4,5,6
});

這樣代碼更加就簡潔,但有一個小小的缺陷:就是不能使用break、continue語句等來中斷函數,也不能使用return語句返回到外層函數。


當然除了以上兩種方法遍歷數組外,還可以使用for-in枚舉方法來遍歷數組:

var arr = [1, 2, 3, 4, 5, 6];


for (var i in arr) {
    console.log(i); //0,1,2,3,4,5 索引
    console.log(arr[i]); //1,2,3,4,5,6 數組項的值
    console.log(typeof(i));  //string,string,string,string,string,string 字符串
}

但是這樣做是一個很糟糕的選擇,爲什麼呢?

  • 在這段代碼中,賦給i的不是實際的值,而是字符串"0","1","2"等(遍歷到字符串類型的鍵--遍歷普通對象的),表示的是數組項在數組中的位置索引,這很可能在無意之間進行字符串計算,如:"2" + 1 = "21"等情況,所以會帶來不必要的麻煩。
  • for-in除了可以遍歷數組外,我們還知道可以遍歷自定義屬性,也就是可以枚舉 可枚舉屬性,那麼在遍歷數組時,它還額外執行一次,用於遍歷可枚舉屬性了,這是我們不需要的操作。甚至還可以遍歷到數組原型鏈上的屬性,這更是一個大麻煩。
  • for-in循環還有一個更大的缺點:那就是它會以隨機次序遍歷數組元素,這更是我們不想要的。也就是說它遍歷出的元素的順序不是數組中真正的順序。
  • for-in循環主要用於遍歷普通對象的,用於遍歷字符串類型的鍵,也就是對象的屬性名(鍵名)。不適用於遍歷數組。


以上所列舉的方法可以都有缺點,那麼用什麼方法來遍歷數組更好呢?


for-of循環

在ES6中,有一個新的特性for-of循環可以用來遍歷數組:

var arr = [1, 2, 3, 4, 5, 6];

for (var i of arr) {
    console.log(i); //1,2,3,4,5,6
}

for-of循環的優點:

  • 這是一種更簡潔、更直接用於遍歷數組的方法
  • 這個方法避開了for-in循環的所有缺點。
  • 與forEach()不同的是,for-of循環可以使用break、continue、return等語句來中斷函數的運行。
  • for-in循環主要用於對象屬性的遍歷。
  • for-of循環用於遍歷數據--如對數組元素的遍歷


for -of對其它集合的遍歷

for-of循環不僅用於數組,還可以用於數組對象等,如DOM中的nodeList等,可以用來遍歷DOM中的子節點、根據給定條件返回的元素節點的集合等。

for-of循環還可以用於遍歷字符串,如:

var str = "hello ES6";

for (var i of str) {
    console.log(i); //h e l l o  E S 6
}

同樣,for-of循環還支持對Map和Set對象的遍歷,這兩個對象到後面會一一講解。


未來JavaScript還有許多的新的集合類型出現,那麼for-of循環就是用來遍歷這些新的集合類型的。


for-of循環不支持對普通對象的遍歷,如果想遍歷普通對象,可以使用for-in循環,for-in循環主要是遍歷對象的屬性的(鍵/值)。



深入理解

for-of循環語句通過 方法調用 來遍歷各種集合。  我們所討論的數組、Map、Set對象以及其它對象有一個共同點:它們都有一個迭代器方法。

我們可以爲任何類型的對象添加迭代器方法。


當我們向任意對象添加[Symbol.iterator]()方法後,就可以遍歷這個對象了。

Symbol是ES6中的一個新特性,所有擁有[Symbol.iterator]()方法的對象被稱爲 可迭代的



迭代器對象

for-of循環的機制

for-of循環首先會調用 [Symbol.iterator]()方法,並返回一個 迭代對象,迭代對象可以是任意有.next()方法的對象,for-of循環會重複調用next()方法,循環一次調用一次。


一個最簡單的迭代器:

var ydq = {

    [Symbol.iterator]: function () {
        return this; //返回新的迭代器對象 ,就是返回ydq對象(this)。
    },
    
    next: function () {
        //返回給for-of循環的結果有兩種可能。
        return {done: false, value: 0};
    }
};

每一次調用next()方法,它都會返回相同的結果,返回給 for-of循環的結果 有兩種可能:(a)沒有完成迭代,(b)下一個值爲0。


我們簡單瞭解了一下for-of循環的機制,現在寫一個簡單的for-of循環,按下列方法調用重寫被迭代的對象。

首先是for-of循環:

for (var i of obj) {
    //一些語句
}

接着,使用下列方法和部分臨時變量實現一個與前面相似的例子:

//調用[Symbol.ietrator]()方法,並返回新迭代對象$ietrator
var $ietrator = obj[Symbol.ietrator]();
//接着新迭代對象調用next()方法並返回dome,value屬性值
var $next = $ietrator.next();
//確定dome、value屬性值
while (!$next.dome) {
    i = $next.value; //將value屬性值賦值給i。
    //一些語句
    
    $next = $ietrator.next(); //並繼續調用next()方法。
}

經過以上步驟就可以將集合中的數據一一遍歷出來。

當沒有完成迭代時(dome: false)才繼續迭代下去,並返回value屬性的值給i。


發佈了109 篇原創文章 · 獲贊 56 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章