Array.prototype.map()是否可以对其调用的数组进行突变?

时间:2018-12-17 04:17:49

标签: javascript arrays

Mozilla说:

  

map不会使调用它的数组发生突变(尽管回调,如果   调用,可以这样做)。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

具体来说,回调传递的第三个参数是:

  

调用了数组映射。

我以为这意味着将内存中的数组位置通过引用复制到回调中。

因此,通过更改第三个参数,我们应该更改原始数组,但是以下两段代码会产生冲突的结果:

情况1,重新分配第三个参数不会使原始数组发生变化:

var A = [1, 2, 3];
A.map((v,i,_A) => { 
  console.log("_A is the array map invoked on: ", _A===A); // true
  _A = []; // reassign an empty array
  return v;
});
console.log("'A' did not mutate:", A) // [1, 2, 3] did not mutate

情况2,将第三个参数设置为零长度会改变原始数组:

var B = [1, 2, 3];
B.map((v,i,_B) => { 
  console.log("_B is the array map invoked on: ", _B===B); // true
  _B.length = 0; // clearing the array by setting it zero length
  return v;
});
console.log("'B' has mutated:", B) // [] mutated

很明显,在第二种情况下,原始数组发生了变异(迭代器仅执行一次)。 但是我想念什么呢?为什么会有冲突的结果?

2 个答案:

答案 0 :(得分:5)

在第一种情况下,您只是重新分配-这与突变分开。仅当您使用obj.prop = <someExpression>之类的语法时,才会发生突变。这就是案例2中的情况

_B.length = 0;

_B引用的内存中的对象将更改其.length属性。但是只需重新分配变量名(如_A = [])就不会更改之前碰到的_A所引用的内容-先前由_A引用的对象将会被忽略(保持不变),以后在该范围内对_A的引用将引用刚刚分配给_A的任何内容。

这与Array.prototype.map并没有任何关系-这与您对任何Javascript对象或变量名所见的行为相同,例如:

const obj = { foo: 'foo' };
let anotherObj = obj; // references the original object
anotherObj = {};
// a new object is created in memory and assigned to the variable name `anotherObj`
// but this does not mutate whatever anotherObj happened to refer to before
console.log(obj);

答案 1 :(得分:1)

在JavaScript中,您可能并不熟悉传递的引用。在回调的本地范围内创建对A的引用的本地副本。有关更多信息,请参见此答案:Does Javascript pass by reference?

因此,当您将_A重新分配给一个空数组时,您只是在告诉参考副本指向一个新的空数组。但是,对A的旧引用仍然存在并且未被修改。

当您更改长度时,实际上是在对_A所指对象进行突变。