1

I am puzzled why this following bit of code will return mutations of both the local and global array:

var globalarray = [1,2,3];

 function test(){
     let localarray = globalarray;
     localarray.push(4);
     console.log(localarray);
     console.log(globalarray);
 }
 setInterval(test, 2000);

Returns:

 [1,2,3,4] for both

My impression was that localarray would be a copy of globalarray. I saw another answer that said in order to make a copy of an array you need to use .slice().reverse(), which seems like a workaround. Why does it not just create a new local copy? Is there a simple and efficient way to make a local copy of a global array? Otherwise it seems like making multiple mutations to a global array is terrible for performance.

Bagdan Gilevich
  • 1,231
  • 1
  • 11
  • 17
anesthetic
  • 193
  • 2
  • 18
  • 1
    assignment operator just assign the reference of existing array to new variable. `let localarray = globalarray` will not create a new array and assign to globalarray. what you can do is use spread operator `let localarray = [...globalarray]` but keep in mind that spread operator only do shallow copy. – samee Aug 12 '18 at 00:28
  • Possible duplicate of [Copying array by value in JavaScript](https://stackoverflow.com/questions/7486085/copying-array-by-value-in-javascript) – Sebastian Simon Aug 12 '18 at 00:36

3 Answers3

2

The reason for this in your code is because you are simply telling your test function to point to the globalarray with the = operator. This is because in JavaScript, variable assignments do not inherently "copy" objects into the new variables; this might seem confusing, so just think of the = operator as a sign that points your code to the location of an object.

The only times that the = operator is making new copies is when you are working with primitive types. In those cases, you cannot inherently change what those objects are, so = is sufficient to make a copy like you would expect.

The reason for the .slice().reverse() is to work around the problem you are seeing. Another way you could do this is by using let localarray = globalarray.map(e => e), or as samee suggested, by using let localarray = [...globalarray]. The .map operator takes the function given to it as the first argument and applies it to every element, and then it stores the result in a different array at another location that is not the same as globalarray.

Keep in mind that these methods, and any others that might be suggested to you, are shorthand ways of doing

let localarray = new Array(globalarray.length);
for (let i = 0; i < globalarray.length; i++) {
    localarray[i] = globalarray[i];
}

// localarray can now be freely modified because it does not point to the same array as globalarray

Also keep in mind that if you need to also create copies of the elements inside of the arrays, then you will have to use more comprehensive copying code. There are libraries that can do this sort of heavy-duty copying if you really need it.

Andres Salgado
  • 243
  • 2
  • 7
1

In JavaScript (as in many other languages), objects are passed by reference. Arrays are also passed by reference (because an array is actually a type of object). So when you say: let localarrray = globalarray, you are actually setting localarray to a pointer that resolves to globalarray.

There are several strategies for obtaining a true copy. If you're trying to get a fresh copy of the original array, the Array prototype function of .map() is one of the most targeted tools for the job. It would look like this:

let localarray = globalarray.map(element => element);
1

Simple way to clone an array is just

let localarray = globalarray.slice();

I do it a different way to deep cloning:

clone: function() {
    var clone = undefined;
    var instance = this;

    if ( XScript.is.xobject(instance) ) {
        clone = {};
        for ( var prop in instance ) {
            if ( instance.hasOwnProperty(prop) ) {
                var p = instance[prop];
                if ( XScript.is.xobject(p) ) p = p.clone();
                clone[prop] = p;
            }//END IF this
        }//END FOR prop

        return clone;
    }//END IF xobject

    if ( XScript.is.xarray(instance) ) {
        clone = instance.slice(0);
        return clone;
    }

    return clone;
}//END FUNCTION clone

This clone will require you attaching the clone object to the object prototype and check to see if its an array, object, or other. I am not changing the function to fit all your needs because one should learn to somewhat how to change it and what to do instead of copy pasta. Plus it is just an example.

Deadweight
  • 137
  • 8