0

Can someone explain to me why I am not able to use the apply method on string array correctly?

function speak(line) {
     console.log(line);
}
var whiteRabbit = {type: "white", speak: speak};
speak.apply(whiteRabbit, ["Burp!","Skree","Hello"]);

The output is Burp, why not the whole array? And How to achieve that with the apply method?

adeneo
  • 312,895
  • 29
  • 395
  • 388

5 Answers5

1

Function#apply spreads the array into functions parameters, since your only parameter is line, the first item in the array is assigned to it, and the rest are ignored.

btw - since the speak function doesn't use this in any way, the 1st parameter of apply doesn't matter in this case.

If you'll add more params to the function you can see how it works:

function speak(a, b, c) {
     console.log(a, b, c);
}

speak.apply(null, ["Burp!","Skree","Hello"]);

If you need to display an array of unknown length, it's better to invoke the function using Function#call, and then iterate the array, or convert it to something presentable. For example:

function speak(arr) {
  console.log(arr.join(' '));
}

speak.call(null, ["Burp!", "Skree", "Hello", "Cats"]);
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
1

From Function#apply

The apply() method calls a function with a given this value, and arguments provided as an array (or an array-like object).

You take only the first element of the array as parameter line. If you take more parameters, you could see the rest of the array as well.

function speak(line, line1, line2) {
    console.log(line);
    console.log(line1);
    console.log(line2);
}

var whiteRabbit = {
    type: "white",
    speak: speak
};

speak.apply(whiteRabbit, ["Burp!", "Skree", "Hello"]);

If you like to use the values as array, you yould use arguments and iterate the values.

function speak() {
    Array.prototype.forEach.call(arguments, function (s) {
        console.log(s);
    });
}

var whiteRabbit = {
    type: "white",
    speak: speak
};

speak.apply(whiteRabbit, ["Burp!", "Skree", "Hello"]);

Wit ES6 you could use rest parameters ...

function speak(...args) {
    args.forEach(s => console.log(s));
}

var whiteRabbit = {
    type: "white",
    speak: speak
};

speak.apply(whiteRabbit, ["Burp!", "Skree", "Hello"]);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

I'm going to assume that fatRabbit is meant to be whiteRabbit and that your question is why you only see Burp! instead of the full array.

The reason is that apply uses the array to call your function with discrete arguments, so the first entry shows up as the line parameter, and you're not seeing the others because you don't have parameters for them.

If you want to see the array, use call rather than apply; then line will refer to the array, not just the first entry:

function speak(line) {
     console.log(line);
}
var whiteRabbit = {type: "white", speak: speak};
speak.call(whiteRabbit, ["Burp!","Skree","Hello"]);

Alternately, add more parameters in the method (speak(line1, line2, line3)).


In a comment, you've asked:

Can you show how to make it dynamic?

If by "dynamic" you mean it logs as many entries as it gets, I'd use call (as above) and a loop:

function speak(lines) {
    lines.forEach(function(line) {
        console.log(line);
    });
}
var whiteRabbit = {type: "white", speak: speak};
speak.call(whiteRabbit, ["Burp!","Skree","Hello"]);

That's using forEach, but you have lots of other options.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

You need to add more parameters

function speak(line, line2, line3) {
     console.log(line, line2, line3);
}
var whiteRabbit = {type: "white", speak: speak};
speak.apply(whiteRabbit, ["Burp!","Skree","Hello"]);
marvel308
  • 10,288
  • 1
  • 21
  • 32
0

You may let the rabbit say one word after another:

 ["Burp!","Skree","Hello"].forEach( speak );

If you want to change the context too:

["Burp!","Skree","Hello"].forEach( word => speak.call(rabbit, word));
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151