0

MDN bind

// same as "slice" in the previous example
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.apply.bind(unboundSlice);

// ...

slice(arguments);

when I write like below

function add(num1, num2){
     return num1 + num2;
 }
var test = Function.prototype.apply.bind(add);
var result = test([1,2])

It's wrong. I don't know where I was wrong in my code.

Liuuil
  • 1,441
  • 3
  • 16
  • 22
  • 1
    Possible duplicate of [Javascript call() & apply() vs bind()?](https://stackoverflow.com/questions/15455009/javascript-call-apply-vs-bind) – Karthik RP Nov 28 '17 at 05:04

2 Answers2

1

Function.prototype.apply takes more than just the [1, 2] argument for the argument list – it takes the this argument before it. (docs) In other words, what your code is effectively doing is this:

function add(num1, num2){
    return num1 + num2;
}

var result = add.apply([1, 2]);

and what you want is this:

function add(num1, num2){
    return num1 + num2;
}

var result = add.apply(null, [1, 2]);

achievable thusly:

function add(num1, num2) {
    return num1 + num2;
}

var test = Function.prototype.apply.bind(add, null);
var result = test([1, 2]);

console.log(result);
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • but, why the MDN's example doesn't take the second argument as `null` rather than take the `argument` directly? – Liuuil Nov 28 '17 at 06:18
  • @Liuuil: Which example are you referring to? – Ry- Nov 28 '17 at 06:21
  • [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) , right above #Polyfill – Liuuil Nov 28 '17 at 06:23
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind – Liuuil Nov 28 '17 at 06:39
  • @Liuuil: That’s because it actually wants to call `Array.prototype.slice.apply(arguments)`, not `Array.prototype.slice.apply(null, arguments)`. `arguments` is the “this” argument. – Ry- Nov 28 '17 at 09:46
0

What MDN is doing:

  1. slice is a method of Array objects, but can be applied to array like objects, such as arguments which have a length and numeric string property names, to convert the object into an actual Array object instance:

    Array.prototype.slice.apply( arguments)
    

Note this code does NOT call slice with any parameter values. If any were required, they could be added as an array of values to the actual argument list of apply. It works because slice uses its this value (set to arguments) as the array like object, and will operate without any additional parameters.

  1. apply is a method of function objects, and in the code above, is inherited from Function.prototypeby theslice` function.

Now break down the code in (1) above into two pieces:

const slice = Array.prototype.slice   // a) 
slice.apply( arguments)             // b) and c)

a) creates a reference to the slice function stored in Array.prototype.

b) calls slice's apply method, inherited from Function.prototype, with a this value of slice for simple reason that apply is being called as a method of slice.

c) apply calls its this value (slice) with slice's this value set to the first argument supplied to apply.

But notice in the broken down code the apply function is called with a constant this value - namely the slice function. If we bind apply to slice we can compress all the steps into a single function call:

const slice = Array.prototype.slice;
const boundApply = slice.apply.bind(slice);

making boundApply( arguments) equivalent to

 Function.prototype.apply.bind(Array.prototype.slice)(arguments)

While the MDN example puts this bound version of apply in a variable called slice, the resultant function's argument syntax is that of Function.prototype.apply. Because of this start and end parameters for slice can be added as the second and third arguments of the bound function.

Hence your example needs to supply an argument list suitable for apply, not add

function add(num1, num2){
 return num1 + num2;
}
var test = Function.prototype.apply.bind(add);
var result = test(null, [1,2])

The reply from @Ryan shows how to wrap this into a single function that does not require null.


Summary

Function.prototype.bind is used to create an exotic function with a specific this value. Even if you save the the bound function as an object property and call it as a method of the object, the this value it sees is the one that was supplied to bind. This can be useful for, say, event handlers that use a this value other than null, window or the element on which the event was fired.

Function.prototype.apply allows you to dynamically supply the this value of a called function. It may be more efficient than using bind for a single call to an existing or anonymous function (because it does not require creating a bound function object) or may suit an application that wants to call the same function on multiple objects to be used as the function's this value.

Note that bind and apply only affect the this value of functions declared using the function keyword. You can not bind the this value of arrow functions in JavaScript.

traktor
  • 17,588
  • 4
  • 32
  • 53