1

I quite understand the basic principle of using .apply() method on JS.

function sayHi(x, y, z) {
  console.log("I'm " + this.name + ", My choices are" + x + "," + y + "," + z);
}
var personA = {
    name : "Albert"
};
var personB = {
    name : "Bob"
};

var name = "Cindy";
var options = [" a", " b", " c"];

sayHi.apply(personA, options); // "I'm Albert, My choices are a, b, c"
sayHi.apply(personB, [" d", " e", " f"]); // "I'm Bob, My choices are d, e, f" 

Above snippet is an ideal case where you just want to use certain amount of array's element in sayHi() function and you pass on the exact same amount of data (array) needed for sayHi() function.

However, sometimes you need to utilize all of the array's element in given data set where the data could also be in varying amount. So instead of just accepting array with 3 elements, the sayHi() function can accept and array with 4,5, 6, or more elements, and not just accepting it but also utilizing all of the elements passed, something like this:

function sayHi(....) {
  // Accept any array with varying amount of elements, and using it
  for (...) {
    // A loop that will go through each element in given array
  }
}
var personA = {
    name : "Albert"
};
var personB = {
    name : "Bob"
};

var name = "Cindy";
var options3 = [" a", " b", " c"];
var options4 = [" a", " b", " c", " d"];
var options5 = [" a", " b", " c", " d", " e"];
// and so on

sayHi.apply(personA, options3);
sayHi.apply(personA, options4);
sayHi.apply(personA, options5);

and so far I haven't been able to find a way to do this, so I need your help to explain it to me.

Thanks,

xcode
  • 1,637
  • 3
  • 16
  • 25
  • You can pass in an object with name value pairs that are the properties to be created and their associated values. Then you can use *for..in* to iterate over the object's properties (or *Object.keys(params).forEach(...)*). – RobG Aug 22 '16 at 03:43
  • 1
    Old-school JS: use the `arguments` object. ES6 onwards: use [rest parameters](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/rest_parameters). – nnnnnn Aug 22 '16 at 03:44
  • @nnnnnn—where "old school" means way more than half the browsers in use. – RobG Aug 22 '16 at 05:21

2 Answers2

2

You can use 3 different approaches.

First, you could use the arguments array-like object instead of x, y and z.

function sayHi() {
  for(var choice in arguments){
    // Do stuff.
  }
}

function sayHi() {
  // Note that arguments is not an array but only an array-like object.
  var choicesStr = "My choices are " + Array.prototype.join.call(arguments, ", ");
  console.log("I'm " + this.name + ", " + choicesStr);
}
var personA = {
    name : "Albert"
};
var personB = {
    name : "Bob"
};

var name = "Cindy";
var options = ["a", "b", "c"];

sayHi.apply(personA, options); // "I'm Albert, My choices are a, b, c"
sayHi.apply(personB, ["d", "e", "f", "i", "j"]); // "I'm Bob, My choices are d, e, f"

The drawback of this approach is that arguments will contain every argument. If you need to provide a first argument that should be treated differently, you will have to extract it first.

Second, you could make use of ES6 rest parameter functionality.

function sayHi(...choices) {
  for(var choice in choices){
    // Do stuff.
  }
}

function sayHi(...choices) {
  // Note that unlike arguments, the rest parameter is a real array.
  var choicesStr = "My choices are " + choices.join(", ");
  console.log("I'm " + this.name + ", " + choicesStr);
}
var personA = {
    name : "Albert"
};
var personB = {
    name : "Bob"
};

var name = "Cindy";
var options = ["a", "b", "c"];

sayHi.apply(personA, options); // "I'm Albert, My choices are a, b, c"
sayHi.apply(personB, ["d", " e", " f", "i", "j"]); // "I'm Bob, My choices are d, e, f"

The advantage is that can easily provide heading parameters that will be considered separately.

function sayHi(firstArg, ...choices) {
  for(var choice in choices){
    // Do stuff.
  }
}

The drawback of this approach is that its support is not yet widespread. If this is a problem, you can use a transpiler like Babel.

Third, you could just pass an array with call instead of apply

function sayHi(choices) {
  var choicesStr = "My choices are " + choices.join(", ");
  console.log("I'm " + this.name + ", " + choicesStr);
}
var personA = {
    name : "Albert"
};
var personB = {
    name : "Bob"
};

var name = "Cindy";
var options = ["a", "b", "c"];

sayHi.call(personA, options); // "I'm Albert, My choices are a, b, c"
sayHi.call(personB, ["d", " e", "f", "i", "j"]); // "I'm Bob, My choices are d, e, f"
Quentin Roy
  • 7,677
  • 2
  • 32
  • 50
0

You want to use the arguments object of a function, which gives you an array of all arguments passed in, whether named or not.

function sayHi(){  
  for (var i=0;i<arguments.length;++i){
    console.log( "Hi "+arguments[i] );  
  }
}

var parents = ["Mom","Dad"];
var children= ["Suzie","Jacob","Jerome","Sandra"];
sayHi.apply(this,parents);
sayHi.apply(this,children);

Note, however, that if you're going to pass an array of objects into a function, you can also, you know, just pass in the array, instead of jumping through apply and arguments:

function sayHi(people){
  people.forEach(function(name){
    console.log( "Hi "+name );  
  });
}

var parents = ["Mom","Dad"];
var children= ["Suzie","Jacob","Jerome","Sandra"];
sayHi(parents);
sayHi(children);
Phrogz
  • 296,393
  • 112
  • 651
  • 745