4

I am trying to understand MDN's documentation on .push() and .apply() because I'm having an issue where I am ending up with an array inside an array in a project. I have set up some experimental code to illustrate my problem.

Can anyone explain why the array contents inside foo() print within another array? I am not understanding why it isn't printing one array for both console.log()instances.

var animals = [];
var chickens = 'chickens';
var cows = 'cows';

animals.push(cows);
animals.push(chickens);

console.log(animals); // > Array ["cows", "chickens"]

function foo(...animals) {
  console.log(animals); // > Array [["cows", "chickens"]] <-- why is this one inside another array?
}; 

I thought using .apply() would solve the problem but it I couldn't get it to work. For example...

animals.push.apply(animals, cows);
animals.push.apply(animals, chickens);

// Error: second argument to Function.prototype.apply must be an array
Jack Bashford
  • 38,499
  • 10
  • 36
  • 67
dumdum3000
  • 77
  • 1
  • 5
  • 1
    Thats what `...` does.. in the same way as just using `arguments` its going to be an array, so you passed in one argument it will be in `animals[0]` which is the value you passed in, pass in 2 your see 2 elements. – Lawrence Cherone Apr 20 '19 at 02:23
  • 1
    This is what `...` spread/rest operator does. Check details https://stackoverflow.com/questions/31048953/what-do-these-three-dots-in-react-do/54968890#54968890 – Code_Mode Apr 20 '19 at 02:34

2 Answers2

4

Because ... (rest/spread syntax) makes a new array out of the passed arguments - so making an array out of ["chickens", "cows"] will result in [["chickens", "cows"]]. Solve this by removing the ... in foo.

var animals = [];
var chickens = 'chickens';
var cows = 'cows';

animals.push(cows);
animals.push(chickens);

console.log(animals); 

function foo(animals) {
  console.log(animals); 
}; 

foo(animals);
.as-console-wrapper { max-height: 100% !important; top: auto; }
Jack Bashford
  • 38,499
  • 10
  • 36
  • 67
  • 1
    Also, naming the function parameter the same as the global variable can cause confusion. – Derek Apr 20 '19 at 02:38
  • 1
    Yes @Derek, however it will always work because JavaScript looks for variables with the same name in the current scope first before moving outwards one layer - so local variables in a function would take precedence over global variables of the same name. – Jack Bashford Apr 20 '19 at 02:40
  • 1
    Yes, simply called as "Variable Shadowing". But in any case, @Derek is right, naming the parameter the same as a variable will surely lead to confusion. – Ajay Apr 20 '19 at 02:50
3

Read about this -> Rest parameters

// "Rest parameters" receives the arguments which is 
// a like array object, and uses its indexes for creating an array.
function fn(...params) {
  console.log(params);
} 

fn("Ele", "From", "Stack"); // Multiple params will be spread as indexes of the array.
fn(["Ele", "From", "Stack"]); // In this case, one param (an array) will be used as the only index in the array.
fn(); // In this case, an empty array will be generated.
.as-console-wrapper { max-height: 100% !important; top: 0; }

On the other hand, the function apply, the second param should be an array which depicts the arguments

Array.push.apply(animals, [cows, chickens]);
Ele
  • 31,191
  • 6
  • 31
  • 67