简体   繁体   中英

Javascript function not modifying array (reference?)

If JavaScript passes a function argument as a reference on the original object, why can´t I modify the original array with this simple function?

var array1 = ["one"];

function change(array) {
   var array2 = ["222"];
   array = array2;
}

change(array1);

console.log(array1); // this prints ["one"] instead of ["222"]

Why sometimes objects seem to be passed as reference and in this case it´s passed as a copy?

Because the parameter array isn't the same as array1 . They are separate variables. Note that variables are pass-by-value, for objects it's passing a copy of the reference by value. So you would need to do:

var array1 = ["one"];

array1 = change(array1);

function change(array) {
   var array2 = ["222"];
   array = array2;
   return array;  
}

console.log(array1);

Why sometimes objects seem to be passed as reference and in this case it´s passed as a copy?

It's not passed as a copy of the array, it's passed as a copy of the reference to the array. There is still only one array, and you can change the array in the function using that reference:

var array1 = ["one"];

function change(array) {
   array[0] = "222";
}

change(array1);

console.log(array1); // this prints ["222"]

What you can't do is to replace the array with a different array in the function. If you assign a new array to the parameter then it will point to the new array, but the variable array1 is still unchanged and points to the original array.

The way JavaScript memory storage works is with a stack of Execution Contexts. Each one of these Execution Contexts has a Lexical Environment, and a Variable Environment.

The Lexical Environment is the set of variables that came from all the parent Execution Contexts, for example, the variables saved in the global context will always be available for this reason.

The Variable Environment is the set of variables that are being declared in the current Execution Context. This is what you are changing in your example, the Variable Environment variable.

function change(array) {
    var array2 = ["222"];
    array = array2;
}

In this example, array is saved in the Variable Environment. Then, array2 is also saved in the Variable Environment. As you can see, the Lexical Environment is not changed here at all. So once execution completes in the function, and control returns, this Execution Context loses scope and is eligible for garbage collection since it has no ties to any Lexical Environments.

That is why the process you used did not replace the array you passed in. You merely replaced a value in the local scope.

You can still modify the array passed in and it will change the array itself, but if you assign to that variable then it will no longer be changing the array.

The reason you see what you see is because all objects in javascript, arrays are considered an object, are passed by reference. When you initialize array2 it creates a new place in memory for that array, a new reference. Then in the change function the parameter array is a reference to array1 but when you set array equal to array2 that variable has had its reference changed to a new spot in memory, the spot where array2 resides.

Fiddle: http://jsfiddle.net/31s3LLjL/1/

var array1 = ["one"];
var array2 = ["one"];
var array3 = ["one"];

function change(array) {
   var array2 = ["222"];
   array = array2;
}

function change2(array) {
   array[0] = ["222"];
}

function change3(array) {
   var array2 = array;
   array2[0] = ["222"];
}

change(array1);
change2(array2);
change3(array3);

console.log(array1); // prints one
console.log(array2); // prints 222
console.log(array3); // prints 222

In the first change function we initialize a new array (object). In the other two change functions we only work on the same references to a single place in memory.

The problem is that you indeed have a call by reference, but then change the reference itself inside your function, not the value referred to.

What you intended to do is this:

var array1 = ["one"];

function change(array) {
   var value = "222";
   array[0] = value;
}

change(array1);

console.log(array1); // this prints ["222"]

A more generic approach would be to use indeed a new array2 inside your function and return (!) that array to the caller. This is of course not a change of an array in place, but when calling such function, you just assign the returned value back to the original array, and you achieve the same.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM