问题
- for…in 和 for…of 迭代时的问题。
- every()和some()方法为什么需要return? 原理是什么?
- bable语法糖?
解答
1. for…in 和 for…of 遍历时的问题。
1.1 问题复现1
let obj = {
a: 1,
b: 2,
c: 3
};
let arr = [1, 2, 3, 4, 5];
现有一个对象和一个数组,分别使用for..in
对arr
和obj
进行遍历,使用for..of
对arr
进行遍历,让arr
中每一项和obj
中每一项的value值都加1。如下:
for (let key in obj) {
obj[key] ++;
}
console.log(obj);
for (let key in arr) {
arr[key] ++;
}
console.log(arr);
for (let item of arr) {
item ++;
console.log(item, arr);
}
console.log(arr);
1.使用for...in
对arr
和obj
进行操作发现:
obj: {a: 2, b: 3, c: 4}
arr: [2, 3, 4, 5, 6]
是没问题的。
2.使用for...of
对arr
进行操作,控制台打印发现:
每一项都加1了,但是arr
没改变。
为什么会出现这种问题?
查阅文档发现:可迭代协议
可迭代协议
: 可迭代协议允许 JavaScript 对象定义或定制它们的迭代行为,例如,在一个for..of
结构中,哪些值可以被遍历到。一些内置类型同时是内置可迭代对象,并且有默认的迭代行为,比如 Array 或者 Map,而其他内置类型则不是(比如 Object))。这里我们注意到Array和Map与Object的迭代行为是不一样的。
当一个对象需要被迭代的时候(比如被置入一个 for…of 循环时),首先,会不带参数调用它的 @@iterator 方法,然后使用此方法返回的迭代器获得要迭代的值。重点在于“返回一个用于在迭代中获得值的迭代器”。
可以看出:for...of 的本质是返回一个迭代器
,迭代器在迭代过程中返回值,而不是直接访问元素,所以无法修改元素。
迭代器如何获取值:迭代器通过
next()
方法返回值,而不是指向地址,所以在for of 迭代中无法改变数组元素
//for ... of内部的实现
try{
//将可遍历对象转换为遍历器
let iter = arr[Symbol.iterator]()
let i = ''
while(i != undefined){
i = iter.next().value
console.log(i)
}
}catch(e){
console.log(e)
}
// [Symbol.iterator]接口
Object.prototype[Symbol.iterator] = function(){
let self = this
let index = 0
let keys = Object.keys(this)
return {
next(){
if(index<keys.length){
return {
value:self[keys[index++]],
done:false
}
}else{
return {
value:undefined,
done:true
}
}
}
}
}
let obj = {
name:'wl',
age:23,
job:'stu',
size:18
}
for(let i of obj){
console.log(i)
}
自定义自定义可迭代对象:
let myIterator = {
next: function() {
},
[Symbol.iterator]: function*() {
yield 1;
yield 2;
yield 3;
}
};
console.log([...myIterator]); // [1, 2, 3]
1.2 问题复现2
let arr = [1, 2, 3, 4, 5];
let obj = {
a: 1,
b: 2,
c: 3
};
根据测试发现,在循环内部直接对数组或者对象添加一个对象,是无法改变index下标的,使用普通的for循环或for...of
也出现同样的情况,为何?
arr.a
的时候相当于在原先的的数组上新增了一个对象。约等于arr.push(8)
,push进去一个对象,:javascript
在循环的时候,去更改数组,是无法改变当前循环的数组的。换个火狐浏览器就可以看出来最后一行的打印是浏览器行为,别被蒙蔽了。
火狐下运行:
接下来测试一下push
行为:
为什么用push(4)?push不进去呢?
push进去了,只不过执行
for...in
的时候,你的即时状态是arr[0, 1, 2, 3]
。
for in
、forEach
都是快照遍历,不是链式遍历,运行时,你动态添加的影响不到这个index,index是在编译阶段就确定了{}
中的行为,for循环次数从一开始就被初始的arr长度规定好了。