Iterator
即迭代器,在ES6中加入,它的主要作用是为各种对象提供了统一的访问机制
例如,当我们使用for/of循环,内部其实调用了数组的Iterator
let a=['a','b','c']
for(let item of a){
console.log(item);
}
扩展:for/in和for/of
使用for in 也可以遍历数组,但是会存在以下问题:
1.index索引为字符串型数字,不能直接进行几何运算
2.遍历顺序有可能不是按照实际数组的内部顺序
3.使用for in会遍历数组所有的可枚举属性,包括原型。例如上栗的原型方法method和name属性
所以for in更适合遍历对象,不要使用for in遍历数组,用for of遍历数组。
记住,for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值。
for of遍历的只是数组内的元素,而不包括数组的原型属性
method
和索引name
那么什么是Iterator?
数组的Iterator是通过它的Symbol.iterator属性方法生成的
let a=['a','b','c']
let b=a[Symbol.iterator]()
console.log(b.next()); //{value:'a',done:false}
console.log(b.next()); //{value:'b',done:false}
console.log(b.next()); //{value:'c',done:false}
console.log(b.next()); //{value:underfined,done:true}
数组Symbol.iterator属性方法被调用时,返回当前数组的Iterator,可以通过Iterator的next()方法来访问数组中的各个成员(for/of内部通过对象的Iterator实现循环遍历)
可迭代协议
任意对象,只要实现了可迭代协议,它的内部成员就可以通过统一的语法被检索到
可迭代协议规定
一个对象是可迭代的,当它具有Symbol.iterator属性:该属性是一个无参数函数,被调用是返回一个Iterator(可以看作生成Iterator的工厂函数)
可迭代对象(也就是原生就实现了可迭代协议的对象)
有:array,arguments,set,Generator,Map,String,Typed Array
自定义一个可迭代对象
class Foo{
constructor(item){
this.item=item
}
[Symbol.iterator](){
let index=0;
const {items}=this
return {
next(){
const item =items[index++];
if(item){
return {
value:item,done:false
}
}
else{
return {done:true}
}
}
}
}
}
扩展:扩展运算符(...)
https://blog.csdn.net/qq_30100043/article/details/53391308
扩展运算符内部也是基于Iterator
let c=['a','b','c'];
console.log([...c]); //['a','b','c']
它和for of一样通过数组的Iterator访问数组中的每一个成员。通过它,可以将数组的每一项插入到新的数组中,从而实现数组的浅拷贝
let d=['a','b','c'];
let e=[...d];
console.log(e); //['a','b','c']
console.log(d===e); //false
另外扩展运算符还可以将任意可迭代对象转为数组
let f="晴天";
let f1=[...f]
console.log(f1); //['晴','天']
字符串处理
使用for循环等遍历字符串时,emoji(表情)等包含两个字符的码点会被拆分,而字符串的Iterator按照完成的Unicode码点进行迭代,可以利用这个特性处理包含emoji的字符串,进行字符串的截取,展示长度计算操作
let str='天气晴(emoji)'
for(let i=0;i<str.length;i++){ //不推荐,因为emoji式的表情不会被遍历到
console.log(str[i]);
}
for(let i of str){ //推荐
console.log(i);
}
Generator
Generator既是一个Iterator也是一个可迭代对象,详情见Generator章节