近来看阮一峰阮大神的ES6,方才看到Iterator和for…of轮回这一章,小作笔记跟人人稍微分享一下,不足之处还望人人多多斧正
Iterator(遍历器)就是一种机制;任何数据构造只假如布置了iterator接口,就能够完成遍历操纵(即顺次处理该数据的一切成员);
Iterator的作用有三个:一是为种种数据构造,供应一个一致的、轻便的接见接口;二是使得数据构造的成员能够按某种序次分列;三是ES6制造了一种新的遍历敕令for…of轮回,Iterator接口重要供for…of消耗。(阮大神原话);
只假如一个对象布置了Symbol.interator接口,就能够用for…of遍历该对象,同时也能够挪用该接口的Symbol.interator要领挪用next()要领对对象举行遍历,差别的是for..of是对该对象的值的输出,而next()返回的是对象。
比方下面的例子:
假如挪用next要领就是
挪用next()要领会返回一个对象{value:value;done:true or false};直到对遍历对象的值方便完成以后,next()要领会返回一个{value:undefined; done:true}代表已遍历完成,再挪用next()要领也不会报错然则依旧会返回{value:undefined; done:true};
有一些对象是原生就封装好的Symbol.iterator接口,能够直接挪用,固然也能够直接用for…of遍历;
在ES6中,有三类数据构造原生具有Iterator接口:数组、某些相似数组的对象、Set和Map构造。
假如没有原生的Symbol.iterator接口,想用for…of遍历,就须要自身在该对象中布置Symbol.iterator接口,比方
一个对象假如要有可被for…of轮回挪用的Iterator接口,就必须在Symbol.iterator的属性上布置遍历器天生要领(原型链上的对象具有该要领也可)。
一个对象假如要有可被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);
}//阮大神案例
上面代码是一个类布置Iterator接口的写法。Symbol.iterator属性对应一个函数,实行后返回当前对象的遍历器对象。
原型链上布置Symbol.iterator接口
function Obj(value){
this.value = value;
this.next = null;
}
Obj.prototype[Symbol.iterator] = function(){
var iterator = {
next: next
};
var current = this;
function next(){
if (current){
var value = current.value;
var done = current == null;
current = current.next;
return {
done: done,
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
对象内部布置
let obj = {
data: [ 'hello', 'world' ],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
};
也就是说假如一个对象没有Symbol.iterator接口,能够在类自身上面布置,也能够在原型连上布置,也能够在对象内部布置
关于相似数组的对象(存在数值键名和length属性),布置Iterator接口,有一个轻便要领,就是Symbol.iterator要领直接援用数组的Iterator接口。
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
// 或许
NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
[...document.querySelectorAll('div')] // 能够实行了
细致请看例子
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'
}
**然则请记着,这个要领仅仅适用于类数组对象,上面的也能够直接用Array.from(iterable)转换成数组来遍历,比方
let arrayLike = {
length: 2,
0: 'a',
1: 'b'
};
for (let x of Array.from(arrayLike)) {
console.log(x);
}//a b
关于一般对象这两个要领是不管用的,**比方
let iterable = {
edition: 'a',
writer: 'b',
read: 'c',
length: 3,
};
for (let item of Array.from(iterable)) {
console.log(item);
}
上面的代码就会输出三个undefined
let iterable = {
edition: 'a',
writer: 'b',
read: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
console.log(item); //报错
}
上面的代码就会抛非常的;
实在ES6许多处所都用的到Iterator这个接口,比方:
解构赋值
扩大运算符
yield*
末了须要说下,字符串既是类数组对象同时自身也有原生Symbol.iterator接口能够直接挪用,比方
var str = “hell”;
for(let v of str){
console.log(v);//”h”,”e”,”l”,”l”
}
关于字符串来讲,for…of轮回另有一个特性,就是会准确辨认32位UTF-16字符。
for…of 区分于for轮回,for轮回比较贫苦,然则是最原始的要领;
for…of 区分于数组的forEach要领,由于forEach要领是从头至尾实行,不会跳出,然则碰到break或许return,continue会跳出轮回
有着同for…in一样的简约语法,然则没有for…in那些瑕玷。
差别用于forEach要领,它能够与break、continue和return合营运用。
供应了遍历一切数据构造的一致操纵接口。
更细致的请检察阮大神(http://es6.ruanyifeng.com/#docs/iterator)本章内容