Trying to understand apply()

Hej!

I’m trying to understand call, bind and apply a bit better and was wondering why my below code is not working;

let obj = {
    num : 2
}

const arr = [4,2,3]

let addToThis = function(arr){
    return this.num + arr.reduce(function(accu,next) {
        return accu + next
    },0)}

console.log(addToThis.apply(obj,arr))

This will spit out “arr.reduce is not a function at Object.addToThis” in the console.

In my head , when im using apply, im passing an array (arr) which the function addToThis will use as an argument. Then I would like to reduce (accumulate) that array and return the sum of the arrays elements together with the objects property value e.g [4,2,3] + 2 = 11.

Thanks! <3

Hi @MSPa1nT ,

I am not confident about the apply() method, but your code works if you use the rest parameter in the function.

Hope this helps

1 Like

Hej Manupillai16,

Thanks for answering, although could you clarify with code as to what you mean?

apply() requires that any arguments be placed in a single array. If an argument happens to be an array itself, it needs to be put inside another array. In other words, either of the below should work for you:

addToThis.call(obj, arr)
addToThis.apply(obj, [arr])

Further reading: Function.prototype.apply() - JavaScript | MDN (mozilla.org)

1 Like

Hej Gaac510,

My understanding is that im declaring an array in the variable arr, which i then use as the arg for the apply(), which should satisfy what you mean is required below, or?

addToThis.apply(obj, [arr])

reduce() is an array method, so when you want to do arr.reduce(...), arr needs to be an array for it to work .

Now consider what happens when you supply arr to apply() without first wrapping arr in an array: apply() will strip arr off its own brackets (i.e. [4, 2, 3] becomes 4, 2 and 3) and try to call the reduce() method on what’s inside (or the first element), which obviously will not work.

Let’s try to make this even easier to understand, when you have:

addToThis.apply(obj, [[4, 2, 3]])

your function is doing:

[4, 2, 3].reduce(...) // Sure no problem.

And when you have:

addToThis.apply(obj, [4, 2, 3])

your function is trying to do:

4.reduce(...) // Won't work.
3 Likes

@MSPa1nT ,

By rest parameter, I meant this:

let addToThis = function(…arr)

The logic is similar to what @gaac510 suggested. (…arr) or the rest parameter takes different number of arguments and stores it in an array.

To understand this and the error which you were getting, try console.log(arr) inside your function before and after adding the rest parameter (…arr)

1 Like

@gaac510

I was reading through this entire thread, trying to understand the cause of the issue OP was encountering. I read the MDN doc for rest , apply() , bind() , & reduce() and was still confused… the example used in the MDN doc is a very simple one.

Excellent example! It made everything crystal clear! Thanks so much for that!

The doc didn’t explicitly state give any examples they way that you did up there.
I suppose an experienced programmer is able to just to infer it from the doc.

(some docs seem really straightforward, other docs seem to be written by seasoned programmers for seasoned programmers, kinda makes sense though as to why that’s the case).

@manjupillai16

When I tried placing console.log(arr) without the rest inside the OP’s function:

 //<without the "rest"
let addToThis = function(arr){
console.log(arr); 
    return this.num + arr.reduce(function(accu,next) {
        return accu + next
    },0)}

I expected to see 4 in the console followed by

“TypeError: arr.reduce is not a function”

instead of [4 ,2, 3], as with thte rest parameter.

But instead, I just got the TypeError .

I’m guessing because it catches the error and aborts before it even gets to the console.log() inside the function? But I get the point you are trying to make.

With the rest, I got:

[{
  num: 2
}, [4, 2, 3]]
"undefined0[object Object]4,2,3"

was using jsfiddle to test…

Both great, insightful answers, though!

EDIT:

I must have inadvertently changed the original code :blush:

console.log() output, first with the rest parameter and then without
2nd attempt with original code:

apply-output-with-without-rest

results as expected… and totally compliments gaac510’s example. Thanks!

Hey @a_aramini ,

Glad that you found the answer useful.

When I said, use console.log(arr), I meant without reduce function to check the value of arr with and without the rest parameter, as below:

let addToThis = function(arr){
       console.log(arr); 
      return this.num;
}

In the above case, it returns 4 and after using (…arr), it returns [4,2,3]

1 Like

Yes, totally see it now, deleted my junk from fiddle, re-pasted @MSPa1nT’ original code and your suggestion worked! :smiley:

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.