forEach、for...in、for...of

forEach

   數組實例的遍歷方法es6

const arr=['red', 'green', 'blue'];
arr.forEach(function(element, index) {
    console.log(element);// red green blue
    console.log(index);// 0 1 2
});

  forEach這種寫法的問題是,沒法中途跳出forEach循環,break命令或return命令都不能奏效。數組

for...in

   JavaScript原有的循環,只能得到對象的鍵名,不能直接獲取鍵值。數據結構

var arr = ['a', 'b', 'c', 'd', 'e'];
for(let i in arr) {
    console.log(i);//0 1 2 3 4
}
for(let index in arr) {
console.log(arr[index]);// a b c d e
}
let es6 = {
    edition: 6,
    committee: "TC-39",
    standard: "ECMA-262"
};
for(let e in es6) {
    console.log(e);
}
//edition
//committee
//standard

  for...in循環有幾個缺點:ide

    數組鍵名是數字,可是for...in循環是以字符串做爲鍵名"0","1","2"等函數

    for...in循環不只遍歷數字鍵名,還會遍歷手動添加的其它鍵,甚至包括原型鏈上的鍵。spa

    某些狀況下,for...in循環會以任意順序遍歷鍵名。設計

  總之,for...in循環主要是爲遍歷對象爲設計的,不適用於遍歷數組。code

for...of

  ES6借鑑C++、Java、C#和Python語言,引入了for...of循環,做爲遍歷全部數據結構的統一的方法。一個數據結構只要部署了Symbol.iterator屬性,就被視爲具備iterator接口,就能夠用for...of循環遍歷它的成員。也就是說,for...of循環內部調用的是數據結構的Symbol.iterator方法。for...of循環可使用的範圍包括數組、Set和Map結構、某些相似數組的對象(好比arguments對象、DOM NodeList對象)、Generator對象以及字符串。對象

  數組原生具備iterator接口(即默認部署了Symbol.iterator屬性),for...of循環本質上就是調用這個接口產生的遍歷器,容許遍歷得到鍵值blog

var arr = ['a', 'b', 'c', 'd', 'e'];
for(let i of arr) {
    console.log(i);//a b c d e
}

  for...of循環能夠代替數組實例的forEach方法

  for...of循環調用遍歷器接口,數組的遍歷器接口只返回具備數字索引的屬性;這一點與for...in也不同。

let arr = [1,3,5];
arr.foo = 'hello';
for(let i in arr) {
    console.log(i);//'1', '3', '5', 'foo'
}

for(let i of arr) {
    console.log(i);//'1', '3', '5'
}

  Set和Map結構也原生具備Iterator接口,能夠直接使用for...of循環

var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for(var e of engines) {
    console.log(e);
}
//Gecko
//Trident
//Webkit
var es6 = new Map();
es6.set("edition", 6);
es6.set("committee", "TC39");
es6.set("standard", "ECMA-262");
for(var [name, value] of es6) {
    console.log(name+ ":" + value);
}
//edition: 6
//committee: TC39
//standard: ECMA-262

  Set和Map遍歷的順序是按照各個成員被添加進數據結構的前後順序。其次,Set結構遍歷,返回的是一個值。Map結構遍歷返回的是一個數組,該數組的兩個成員分別爲當前Map成員的鍵名和鍵值。

  for...of循環,得到數組的索引,能夠藉助數組實例的entries方法和keys方法。

let arr = ["a", "b", "c"];
for(let pair of arr.entries()) {
    console.log(pair);
}
//[0, 'a']
//[1, 'b']
//[2, 'c']

  for...of遍歷相似數組的對象(String、DOM NodeList、arguments)

//字符串
let str="hello";
for(let s of str) {
    console.log(s);// h e l l o
}
//DOM NodeList對象
let paras = document.querySelectorAll("p");
for(let p of paras) {
    p.classList.add("test");  
}
//arguments對象
function printArgs() {
    for(let x of arguments) {
        console.log(x);
    } 
}
printArgs('a', 'b');
//'a'
//'b'

  對字符串來講,for...of循環還可以正確識別32位UTF-16字符

for (let x of 'a\uD83D\uDC0A) {
    console.log(x);
}
//'a'
//'\uD83D\uDC0A'

  並非全部相似數組的對象都具備Iterator接口,一個方法是用Array.from方法將其轉換爲數組

let  arrayLike = [length: 2, 0: 'a', 1: 'b'];
for(let x of array.from(arrayLike)) {
    console.log(x);
}

  對於普通的對象,for...of結構不能直接使用,必須部署Iterator接口後才能使用。一種解決方法是將對象的鍵名生成一個數組,而後遍歷這個數組:

for(let key of Object.keys(someObject)) {
    console.log(key + ":" + someObject[key]);
}

  另外一個方法是使用Generator函數

function* entries(obj) {
    for(let key of Object.keys(obj)) {
        yield [key, obj[key]];
    }
}
for(let [key, value] of entries(obj)) {
    console.log(key, '->', value);
}
//a -> 1
//b -> 2
//c -> 3

  for...of相對其它遍歷方法,有如下優勢:

    有着同for...in同樣簡潔的語法,可是沒有for...in那些缺點;

    不一樣於forEach方法,它能夠與break、continue和return配合使用

    提供了遍歷全部數據結構的統一操做接口

for(var n of fibonacci) {
    if(n>1000)
        break;
    console.log(n);
}

參考:

Iterator和for...of

相關文章
相關標籤/搜索