Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is apply not already bound to functions in Javascript?

Assume, for the sake of this question, that I want to be able to create a function in Javascript that appends all of the elements of one array to another array. One way to achieve this, if you have access to the destination array, is to say:

var destination = [1,2,3];
var source = [4,5];
Array.prototype.push.apply(destination, source);
console.log(destination); // [1,2,3,4,5]

Now, since Array.prototype.push.apply is pretty ugly, I want to alias it to something nicer, like:

var pushAll = Array.prototype.push.apply;

Which I should be able to call with two arguments, the context (destination) and an array of arguments (source). However, when I try to use the alias, this happens:

pushAll(destination, [6,7]);
TypeError: Function.prototype.apply was called on [object global], which
is a object and not a function

So clearly the apply function is not bound to push, which led me to try this:

var pushAll = Function.prototype.apply.bind(Array.prototype.push);
pushAll(destination, [6,7]);
console.log(destination); // [1,2,3,4,5,6,7,8]

Which clearly works fine. My question is, why do I have to bind the push method to apply? Shouldn't Array.prototype.push.apply already be bound to apply? Why does calling it under a different name result in calling it on an unbound context?

like image 257
Stankalank Avatar asked Apr 15 '14 17:04

Stankalank


People also ask

What is a function bound to in JavaScript?

A function in javascript is not technically bound to anything. It may be declared as a property of an object as in: But, if you get the function into it's own variable by itself, it is not bound to any particular object.

What is the difference between bind () and apply () in JavaScript?

JavaScript: bind () vs apply () and call () 1 Call ¶ 2 Apply ¶. The apply () method calls the function with a given this value and allows passing in arguments as an array (or an array-like object). 3 Bind ¶. The bind () method returns a new function and allows passing in a this array and any number of arguments.

Is it possible to bind a function to a specific object?

It's possible to bind the function to multiple objects, so it doesn't make sense to look for THE one object to which you bound the function; because you're adding the function as a subset of the object.

How to bind a variable to a particular object in JavaScript?

Here we made a new variable function printFunc2 which refers to the function printFunc () of object geeks. Here the binding of this is lost, so no output is produced. To make sure that any binding of this is not to be lost, we are using Bind () method. By using bind () method we can set the context of this to a particular object.


1 Answers

why do I have to bind the push method to apply?

It's the other way round: You have to bind the apply method to the Array push function - you can bind it to other functions as well! Otherwise apply doesn't know which method to apply with the arguments.

Function.prototype.apply.bind(Array.prototype.push); does call the bind function on the apply function with push as the argument, the argument on which apply is then bound. The resulting function pushAll will, when called, invoke apply on the push function, and pass it's argument (the array and the arguments array) to it.

Shouldn't Array.prototype.push.apply already be bound to apply?

Nope. JavaScript is designed to bind the context at the call of a function, not already when it's being referred to as a property - there is no implicit binding on property access. Otherwise Array.prototype.push would already be bound to Array.prototype, before you could call any Function methods like bind/apply on it and try to use it with a different context.

Why does calling it under a different name result in calling it on an unbound context?

It's not so much different name, but different style. (Unbound) Functions do get their this value set to the object when they are called as a method on it, i.e. when the reference to the called function is a property access: destination.push().

This allows for great flexibility, you can "borrow" functions from an object and call them on other objects, still being the same (unbound) function. This is rather impossible in languages where function objects are no first-class objects.

If functions (even though they were meant to be methods) are called as plain functions (pushAll()), their this value will be undefined (unless in sloppy mode). Read more on the this keyword at MDN.

like image 131
Bergi Avatar answered Oct 19 '22 12:10

Bergi