一.Iterator (遍歷器)的概念:數組
遍歷器(Iterator)就是這樣一種機制。它是一種接口,爲各類不一樣的數據結構提供統一的訪問機制。任何數據結構只數據結構
要部署Iterator接口,就能夠完成遍歷操做(即依次處理該數據結構的全部成員)。函數
Iterator的做用有三個:this
一是爲各類數據結構,提供一個統一的、簡便的訪問接口;prototype
二是使得數據結構的成員可以按某種次序排列;指針
三是ES6創造了一種新的遍歷命令for...of
循環,Iterator接口主要供for...of
消費。code
1.在ES6中,有三類數據結構原生具有Iterator接口:數組、某些相似數組的對象、Set和Map結構:對象
let arr = ['a','b','c'];索引
let it = arr[Symbol.iterator]();接口
iter.next(); // {value:'a',done:false}
iter.next(); // {value:'b',done:false}
iter.next(); // {value:'c',done:false}
iter.next(); // {value:undefined,done:true}
2.對象(Object)之因此沒有默認部署Iterator接口,是由於對象的哪一個屬性先遍歷,哪一個屬性後遍歷是不肯定的,需
要開發者手動指定。
本質上,遍歷器是一種線性處理,對於任何非線性的數據結構,部署遍歷器接口,就等於部署一種線性轉換。
不過,嚴格地說,對象部署遍歷器接口並非很必要,由於這時對象實際上被看成Map結構使用,ES5沒有Map結構,
而ES6原生提供了。
(1).一個對象若是要有可被for...of
循環調用的Iterator接口,就必須在Symbol.iterator
的屬性上部署遍歷器生成方
法(原型鏈上的對象具備該方法也可)。
class RangeIterator {
constructor(start, stop) {
this.value = start;
this.stop = stop;
}
[Symbol.iterator]() { return this; }
next() {
var value = this.value;
if (value < this.stop) {
this.value++;
return {done: false, value: value};
} else {
return {done: true, value: undefined};
}
}
}
function range(start, stop) {
return new RangeIterator(start, stop);
}
for (var value of range(0, 3)) {
console.log(value); // 0 1 2
}
(2).代碼首先在構造函數的原型鏈上部署Symbol.iterator
方法,調用該方法會返回遍歷器對象iterator
,調用該對象
的next
方法,在返回一個值的同時,自動將內部指針移到下一個實例。
function Obj(value) {
this.value = value;
this.next = null;
}
Obj.prototype[Symbol.iterator] = function() {
var iterator = {
next: mynext
};
var current = this;
function mynext() {
if (current) {
var value = current.value;
current = current.next;
return {
done: false,
value: value
};
} else {
return {
done: true
};
}
}
return iterator;
}
var one = new Obj(1);
var two = new Obj(2);
var three = new Obj(3);
one.next = two;
two.next = three;
for (var i of one){
console.log(i); // 1 2 3
}
(3).相似數組的對象調用數組的Symbol.iterator
方法的例子:
let iterable = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
console.log(item); // 'a', 'b', 'c'
}
(4).普通對象部署數組的Symbol.iterator
方法,並沒有效果:
let iterable = {
a: 'a',
b: 'b',
c: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
console.log(item); // undefined, undefined, undefined
}
二.for...of循環:
一個數據結構只要部署了Symbol.iterator
屬性,就被視爲具備iterator接口,就能夠用for...of
循環遍歷它的成員。
也就是說,for...of
循環內部調用的是數據結構的Symbol.iterator
方法。
for...of
循環可使用的範圍包括數組、Set 和 Map 結構、某些相似數組的對象(好比arguments
對象、DOM NodeList 對象)、後文的 Generator對象,以及字符串。
1.for...of
循環能夠代替數組實例的forEach
方法:
const arr = ['red', 'green', 'blue'];
arr.forEach(function (element, index) {
console.log(element); // red green blue
console.log(index); // 0 1 2
});
for(let i of arr){
console.log(i); // red green blue
}
2.JavaScript原有的for...in
循環,只能得到對象的鍵名,不能直接獲取鍵值。ES6提供for...of
循環,容許遍歷得到
鍵值:
var arr = ['a','b','c','d'];
for(let a in arr){
console.log(a); // 0 1 2 3
}
for(let a of arr){
console.log(a); // a b c d
}
3.for...of
循環調用遍歷器接口,數組的遍歷器接口只返回具備數字索引的屬性。這一點跟for...in
循環也不同:
let arr = [3,5,7];
arr.hello = 'hello';
for(let i in arr){
console.log(i); // "0","1","2","3"
}
for(let i of arr){
console.log(i); // "3","5","7"
}