Mozilla said:
map does not mutate the array on which it is called (although callback, if invoked, may do so).
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Specifically, the third argument the callback was passed is:
The array map was called upon.
Which I assumed that means the array location in memory is copy into the callback by reference.
So by mutating the third argument, we should mutate the original array, but the following two pieces of snippet give conflicting result:
case 1, re-assigning the third argument did not mutate the original array:
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
case 2, setting the third argument to length of zero mutates the original array:
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
Clearly in the second case the original array is mutated (the iterator only execute once). But what am I missing ? Why the conflicting result ?
map does not mutate the array on which it is called (although callbackFn , if invoked, may do so). The range of elements processed by map is set before the first invocation of callbackFn .
map() creates a new array from calling a function for every array element. map() calls a function once for each element in an array. map() does not execute the function for empty elements. map() does not change the original array.
Arrays in JavaScript are just objects, which means they can be mutated.
In case 1, you're only reassigning - this is separate from mutation. Mutation will only occur if you have syntax like obj.prop = <someExpression>
. This is what you're doing in case 2 with
_B.length = 0;
The object in memory that _B
references will have its .length
property mutated. But just reassigning a variable name, like _A = []
, won't change whatever _A
happened to refer to before - the object that was previously referenced by _A
will be ignored (left unchanged), and future references to _A
in the scope will refer to whatever was just assigned to _A
.
This doesn't really have anything to do with Array.prototype.map
- this is the same sort of behavior you would see for any Javascript object or variable name, eg:
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);
In JavaScript, things aren’t exactly pass-by reference as you may be familiar with. A local copy of the reference to A is created in the local scope of the callback. See this answer for more info: Does Javascript pass by reference?
Therefore, when you reassign _A to an empty array, you are just telling the reference copy to point to a new empty array. However, the old reference to A still exists and is untouched.
When you mutate length, you are actually mutation the object the _A refers to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With