iterator

iterator-generator

遍歷Array能夠採用下標循環,遍歷Map和Set就沒法使用下標。爲了統一集合類型,ES6標準引入了新的iterable類型,Array、Map和Set都屬於iteratore類型。
全部的iterator對象都有next()方法,會返回一個結果對象。該結果對象擁有兩個屬性,value和done.
下面的例子模擬生成iteratores6

var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}

上例能夠看出,要生成一個iterator很複雜。幸虧ES6專門提供了generator用來生成iterator.數組

generator

generator 是一個返回迭代器的函數,與普通函數不一樣的是聲明generators函數要在function後面添加"*",同時函數內部使用es6新增長的關鍵字yield來控制next()方法的返回值。數據結構

// generator 函數
function *createIterator(){
    yield 1;
    yield 2;
    yield 3;
}

// 建立迭代器
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
console.log(iterator.next().value); // undefined

從上述代碼能夠看出每次的yield使用均可以阻止代碼的執行,當迭代器調用next()方法後纔會繼續執行。
也可使用函數表達式的形式建立generator函數。ide

let createIterator = function *(items){
    for(let i=0;i<items.length;i++){
        yield items[i];
    }
}
let iterator = createIterator([1,2,3]);
console.log(iterator.next()); // "{value:1,done:false}"
console.log(iterator.next()); // "{value:2,done:false}"
console.log(iterator.next()); // "{value:3,done:false}"
console.log(iterator.next()); // "{value:undefined,done:true}"
console.log(iterator.next()); // "{value:undefined,done:true}"

注意: 關鍵字yield只能在generator函數內部使用,即便在生成器內部的函數中也不行。以下代碼:函數

function *createIterator(items){
    items.forEach(function(item){
        yield item + 1;
    })
}

let iterator = createIterator([1,2,3]);
console.log(iterator.next()); // "Uncaught SyntaxError: Unexpected identifier"

在對象中建立生成器。code

var o  = {
	createIterator: function *(items) {
		for(let i =0; i<items.length; i++) {
			yield items[i];
		}
	}
};
let iterator = o.createIterator([1,2,3]);

ES6寫法:orm

var o  = {
	*createIterator(items) {
		for(let i =0; i<items.length; i++) {
			yield items[i];
		}
	}
};
let iterator = o.createIterator([1,2,3]);

iterator與for...of

Iterator 接口的目的,就是爲全部數據結構,提供了一種統一的訪問機制,即for...of循環。當使用for...of循環遍歷某種數據結構時,該循環會自動去尋找 Iterator 接口。
一種數據只要部署了Iterator接口,就認爲這種數據是可遍歷的(iterable)。默認的Iterator接口部署在數據結構的Symbol.iterator屬性,或者說,一個數據結構只要具備Symbol.iterator屬性,就能夠認爲是「可遍歷的」(iterable)。
Symbol.iterator屬性自己是一個函數,就是當前數據結構默認的遍歷器生成函數。執行這個函數,就會返回一個遍歷器。屬性名Symbol.iterator,它是一個表達式,返回Symbol對象的iterator屬性,這是一個預約義好的、類型爲 Symbol 的特殊值,因此要放在方括號內。對象

const obj={
	[Symbol.iterator]: function() {
		return {
			next: function() {
				return {
					value: 1,
					done: true
				}
			}
		}
	}
}
obj[Symbol.iterator]().next();  //  {value: 1, done: true}

上面代碼,obj具備Symbol.iterator屬性,是可遍歷的。執行這個屬性,會返回一個遍歷器對象。該對象的根本特徵就是具備next方法。每次調用next方法,都會返回一個表明當前成員的信息對象,具備value和done兩個屬性。
Array,Map,Set,String,TypedArray,函數的arguments對象,NodeList對象都具備Iterator接口。能夠被for...of遍歷。
注意: 對象(Object)沒有默認部署 Iterator 接口。索引

let values = [1, 2, 3];
for (let num of values) {
    console.log(num);   // 1 2 3
}

for...of首先調用values數組的Symbol.iterator的方法,獲取一個迭代器。而後iterator.next()被調用,迭代器的value屬性被讀出並放入了num變量。num 變量的值開始爲 1 ,接下來是2,最後變成 3 。當結果對象的done變成true,循環就退出了。接口

上例的代碼也可採用下面的方法:

let values = [1, 2, 3];
let iter = values[Symbol.iterator]();
iter.next();    //  {value: 1, done: false}
iter.next();    //  {value: 2, done: false}
iter.next();    //  {value: 3, done: false}
iter.next();    //  {value: undefined, done: true}

ES5中有for...in遍歷對象,那麼for...in和for...of有什麼區別呢?
for ... in循環因爲歷史遺留問題,它遍歷的其實是對象的屬性名稱。一個Array數組實際上也是一個對象,它的每一個元素的索引被視爲一個屬性。當咱們手動給Array對象添加了額外的屬性後,for ... in循環將帶來意想不到的意外效果:

var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
    console.log(x); // '0', '1', '2', 'name'
}

採用for...of的寫法

var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a) {
    console.log(x); // 'A', 'B', 'C'
}

結論:for...in遍歷的實際是key,而for...of遍歷的是value。

集合的迭代器

  • entries() :返回一個包含鍵值對的迭代器;
  • values() :返回一個包含集合中的值的迭代器;
  • keys() :返回一個包含集合中的鍵的迭代器。

entries()

let colors = [ "red", "green", "blue" ];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();

data.set("title", "Understanding ES6");
data.set("format", "ebook");

for (let entry of colors.entries()) {
    console.log(entry);
}

for (let entry of tracking.entries()) {
    console.log(entry);
}

for (let entry of data.entries()) {
    console.log(entry);
}

以上代碼輸出結果:

[0, "red"]
[1, "green"]
[2, "blue"]
[1234, 1234]
[5678, 5678]
[9012, 9012]
["title", "Understanding ES6"]
["format", "ebook"]

values()

注意:數組不支持values()

let colors = [ "red", "green", "blue" ];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();

data.set("title", "Understanding ES6");
data.set("format", "ebook");

for (let value of colors.values()) {
    console.log(value);
}

for (let value of tracking.values()) {
    console.log(value);
}

for (let value of data.values()) {
    console.log(value);
}

以上代碼輸出結果:

TypeError: colors.values(...)[Symbol.iterator] is not a function
1234
5678
9012
"Understanding ES6"
"ebook"

keys()

let colors = [ "red", "green", "blue" ];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();

data.set("title", "Understanding ES6");
data.set("format", "ebook");

for (let key of colors.keys()) {
    console.log(key);
}

for (let key of tracking.keys()) {
    console.log(key);
}

for (let key of data.keys()) {
    console.log(key);
}

以上代碼輸出結果:

0
1
2
1234
5678
9012
"title"
"format"
相關文章
相關標籤/搜索