javascriptarraysalgorithmecmascript-6dynamic-programming

Difference between Array.push() and Spread syntax


Algo Problem Statement: Find the smallest array that adds up to the target sum.

Code Issue: I do not understand the difference in results when:

vs.

Please reference the comment line below.

The Spread syntax returns the correct solution, while the .push() method keeps on pushing onto the same array. I don't understand why it keeps referencing the same array in memory.

Many thanks in advance!

let howSum = (target, arr, memo = {}) => {
    if (target in memo) return memo[target];
    if (target === 0) return [];
    if (target < 0) return null;

    let smallest = null;

    for (let e of arr) {
        if (howSum(target - e, arr, memo) !== null) {
            let result = howSum(target - e, arr, memo);
            // result.push(e);
            result = [...result, e];

            if (smallest === null || result.length < smallest.length) {
                smallest = result;
            }
        }
    }

    memo[target] = smallest;
    return smallest;
};

console.log(howSum(10, [1, 2, 5])); // [5, 5]

Solution

  • array.push(element) vs. array = [...array, element]

    Array.push adds an element to the end of the existing array while the spread syntax creates an entirely new array. For example, the following code will throw an error because we are trying to redefine a const:

    const array = ["foo", "bar"];
    array = [...array, "baz"]; // Uncaught TypeError: invalid assignment to const 'array'
    

    Array.push adds to an existing array, so there is no need to redefine:

    const array = ["foo", "bar"];
    array.push("baz"); // No error; "baz" is successfully added to the end of the array.
    

    Another difference is speed. array.push(element) is ~2,500 times faster than array = [...array, element];


    As pointed out by @FelixKling, the spread syntax itself does not create a new array. You can also use the spread syntax in a function like this: myFunction(...myArray). This will use the array elements as arguments. So in other words, ...myArray will not create a new array, but [...myArray] will. Just a small detail worth noting.


    Why your loop keeps referencing the same array in memory

    The Spread syntax returns the correct solution, while the .push() method keeps on pushing onto the same array. I don't understand why it keeps referencing the same array in memory.

    Objects in JavaScript (JavaScript arrays are objects) are reference types—not value types. Therefore, using the spread syntax, you create a new array (result), but still supply the old array (arr) to your function. When you use Array.push, you modify the array that was supplied to your function. And since you modify the array that was supplied (instead of creating a local one), you will keep calling your function with new values in the array. When you use the spread syntax, you create a new array (so result doesn't reference the arr array), and when you call your function with the arr parameter, you still have the same values as when you first called the function.

    @trincot wrote a neat break down of what is going on in your code.

    Here is an experiment you can do in a JavaScript console:

    const myArray = ["foo", "bar"];
    
    function changeArray(arrayParameter) {
      const arrayVariable = arrayParameter;
      // We are still referencing the array that was supplied to our function, so
      // although it looks like we tried to duplicate the array, arrayVariable.push,
      // arrayParameter.push, and myArray.push will all modify the same array.
      arrayVariable.push("baz");
    }
    
    changeArray(myArray);
    console.log(myArray); // ["foo", "bar", "baz"]