Interator对象
1、Symbol.iterator属性 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of
循环使用。
【终于明白了js的内置方法】属性指向一个方法,以数组来讲,大部分属性名和方法名是相同的,但也有例外,比如:constructor属性指向的是Array方法,Symbol.iterator属性指向的values方法
数组原型上的构造函数constructor,指向Array方法,所以可以这么调用Array方法:
2、可以调用for of的原因
(1)字符串:
String.prototype上有Symbol.iterator属性,该属性对应[Symbol.iterator]方法
let str = "abc";
console.log(str[Symbol.iterator]()) StringIterator {}
let strIter = str[Symbol.iterator]()
console.log(strIter.next().value); a
console.log(str = "123") 123
console.log(strIter.next().value); b
我们知道字符串的原型上是有 Symbol.iterator属性的,即可以通过for of迭代每一项。
我们执行Symbol.iterator属性对应的方法时,获取Iterator对象,比如:字符串的Iterator对象是StringIterator。该对象是可以调用next方法的,因为只有Iterator对象可以调用next方法。
StringIterator对象上的原型上还有Symbol.iterator属性,所以StringIterator对象还可以调用for of进行迭代。
需要注意:str是原始值,当获取到StringIterator对象后,StringIterator对象拿到的是内存中“abc”的地址,当修改str的值的时候,str不再指向“abc”的内存,而是指向“123”的内存,但这不影响StringIterator对象,StringIterator对象依旧会指向“abc”。
但是需要注意:引用值改变后,对应的Iterator对象也会改变。
需要注意的是:Iterator对象通过for of 或next方法都是同样进行迭代,都会修改Iterator对象内的指针,比如:StringIterator对象先执行一次next方法,使得指针后移一位,再进行for of迭代的时候,只会打印 b 和 c的值。
let str = "abc";
let strIter = str[Symbol.iterator]()
strIter.next();
for(let value of strIter) {
console.log(value); b c
}
展开运算符和解构赋值也是调用的iterator接口:
let str = "abc";
console.log([...str]) ["a", "b", "c"]
(2)数组:
Array.prototype上有Symbol.iterator属性,该属性对应的是values方法,和values属性的方法一致
因为数组的原型上有Symbol.iterator属性,即可以通过for of进行迭代每项的值,比如:
let arr = ["a","b","c"];
for(let value of arr) {
console.log(value); a b c
}
我们发现数组原型上的values属性和Symbol.iterator属性都指向values方法,values()
方法返回一个新的 Array Iterator
对象,即Array Iterator {} ,该对象也是Iterator对象,可以调用next方法以及进行for of迭代每项的值。
let arr = ["a","b","c"];
let arrIter = arr.values() || arr[Symbol.iterator](); Array Iterator {}
arrInter.next(); a
arr[1] = 2;
for (let value of arrIter) {
console.log(value); 2 c
}
特别注意:修改原数组会修改对应的Iterator对象;
(3)arguments对象
arguments对象上有Symbol.iterator属性,与数组的情况基本上相同
function arg() {
for (let value of arguments){
console.log(value); a b c
}
let argIter = arguments[Symbol.iterator](); Array Iterator {}
argIter.next(); a
for(let value of argIter){
console.log(value); b c
}
}
arg("a","b","c")
(4)Set对象
跟数组几乎一样的
let set = new Set();
set.add("a").add("b").add("c");
for(let value of set){
console.log(value); a b c
}
let setIter = set.values() || set[Symbol.iterator](); SetIterator {"a", "b", "c"}
console.log(setIter);
setIter.next(); a
set.delete("b")
for(let value of setIter){
console.log(value); c
}
(5)Map对象
Map对象调用entries方法或[Symbol.iterator]方法,都是调用的entries方法,得到Map对象对应的的Iterator对象。
我们知道Map对象的keys和values也会得到Interator对象,但是内容却和Map对象不一样。而entries方法得到的内容是和原本的Map对象内容一致。
所以Map对象的[Symbol.iterator]属性,调用entries方法,得到对应MapIterator对象。
思考:为什么Set对象的[Symbol.iterator]属性调用的是Set对象的values方法?!
let map = new Map();
map.set("1","a").set(true,"b").set([2,3],"c"); Map(3) {"1" => "a", true => "b", Array(2) => "c"}
console.log(map);
for(let value of map){
console.log(value); ["1", "a"] [true, "b"] [[2, 3], "c"]
}
let mapIter = map[Symbol.iterator]() || map.valuse(); MapIterator {"1" => "a", true => "b", Array(2) => "c"}
mapIter.next();
map.set(true,"d");
for(let value of mapIter){
console.log(value) [true, "d"] [[2, 3], "c"]
}
类型数组:TypeArray
与数组一模一样!
let uint8 = new Uint8Array(3);
uint8[0] = 1;
uint8[1] = 2;
uint8[2] = 3;
console.log(uint8); //Uint8Array(3) [1, 2, 3]
for(let value of uint8){
console.log(value); 1 2 3
}
let typeArrIter = uint8[Symbol.iterator](); //Array Iterator {}
console.log(typeArrIter);
uint8[1] = 10;
typeArrIter.next();
for(let value of typeArrIter){
console.log(value); 10 3
}