为什么for of方法不能遍历修改原数组?

按照各方法的定义,以下迭代方法应该都能对数组中的每一项运行传入函数,但是:

//对数组进行迭代
//for方法
let b=[1,2,3]
for(let i=0,len=b.length;i<len;i++){
    b[i]*=2
    }
console.log(b) //[2,4,6]

//forEach方法
...
b.forEach(function(i,j){
    b[j]*=2
    })
...//[2,4,6]

//for in方法
...
let c=Object.keys(b)
for(let i in c){
    b[i]*=2
    }
...//[2,4,6]

//for of方法
...
for(let i of b){
    i*=2
    }
...//[1,2,3]

可以看到for of不会修改原数组并返回,参考诸多文档发现都只提到遍历添加事件,目前只能在for of上使用额外方法才能实现数组遍历修改.最后希望各位答主能给出实现原理角度的提示分析,谢谢!

阅读 8.5k
7 个回答

楼主在我的疑惑文章里没有回复我的评论我就来这里强答一波吧哈哈
以下是个人推断,有错误请指出

第一,先看看MDN的可迭代协议

以下是MDN的可迭代协议:
“可迭代协议允许 JavaScript 对象去定义或定制它们的迭代行为, 例如(定义)在一个 for..of 结构中什么值可以被循环(得到)。一些内置类型都是内置的可迭代对象并且有默认的迭代行为, 比如 Array or Map, 另一些类型则不是 (比如Object) 。”
这里我们注意到Array和MapObject的迭代行为是不一样的

第二,看看对象被迭代的本质

另一段材料:
“当一个对象需要被迭代的时候(比如开始用于一个for..of循环中),它的@@iterator方法被调用并且无参数,然后返回一个用于在迭代中获得值的迭代器。”
重点在于“返回一个用于在迭代中获得值的迭代器。”
这里我们可以看到for of 的本质是返回一个迭代器

第三,迭代器是如何获得值的?

迭代器通过next()方法返回值,而不是指向地址,所以在for of 迭代中无法改变数组元素

参考材料:https://developer.mozilla.org...

由上到下,4个方法

  1. 你确定能跑? 即便是能跑,return 了就不会循环了,console 的结果是你猜的吧,
  2. (v,i) b[i]*=2
  3. 没毛病
  4. 参考 2.

因为你操作的只是基本类型啊
var arr=[{}]
for(let i of arr){
i.aa=1
}

我的判断是,题主的编程基础还比较弱,这种情况应该看书看教程。基础提高了,自然会理解,现在光靠文字跟你说,可能说不懂。
另外,第一个例子 console.log 的结果也应是 [1,2,3] ,你大概弄错了。(问题被修改前)

回答你关于for-of的事,for(const a of b)实质是,for(let i = 0, len = b.length, a; i < len; ++i){a = b[i]; ...}
注意了,b的长度是事先被缓存的。

JS中,没有指针或者引用赋值这种东西,a=b[i]不意味着a&=b[i]或者a=&b[i],对基础类型而言,始终是值的复制,对对象/数组/函数而言,始终是传引用。
上面 a = b[i] 只是值的复制(因为你的例子中是数字),a 和 b[i] 相互无关。

因为for of ,forEach都是让item=数组的每一项,如果是基础类型那么就是一个值,你给item重新赋值的时候修改的事item的值跟数组里的每一项已经没有关系了;但是如果数组里的每一项是object时,item=数组每一项,此时item是指向这个对象的地址,所以你如果没有重新赋值,而是使用item.a=1,这样就相当于修改了数组里每一项对象的属性值

推荐问题
宣传栏