In Javascript is there equivalent to .apply that doesn't change the value of this?

Seems easy enough, i want to call a function with array of arguments. Sure, i can say func.apply(this, ['some', 'arguments']); but that will change the value of this inside func. Any idea how to do this without changing it?


Solution 1:

You cannot, because of the way this works in JavaScript. Read on:

Going by the "Entering An Execution Context" section of the ECMAScript spec: when you call a function, the value of this is determined by what's to it's left (called the activation object) . Let's create a function called steve, and put him in an object:

function steve(){}
var obj = { method: steve };

…when we call steve as obj.method(), his this is obj, because obj was the activation object.

The tricky case is when nothing is to the left of a function call:

steve(); // Who am I ?!

There's nothing to the left of the function call — effectively, it's null — so the value of this is set to a default value of the global object (window in web browsers, global in Node.js, etc.).

So you are, in fact, setting a function's this every time you call it.

P.S. calling steve.apply(null, []) is equivalent to calling steve().

Solution 2:

Note that in ES6 you can also write:

func(...someArray)

Here this becomes Window inside func, which is of no use. But if you write:

obj.func(...someArray)

this in inside func will be obj.

This may be the feature i was looking for 5 years ago, but that was 5 years ago, so who remembers :)

Solution 3:

The value of this is no mystery when calling a function, depending on how it is called "normally" (without call or apply):

func(); // `this` is the global object, or undefined in ES5 strict mode
obj.func(); // `this` is `obj`

So to avoid "changing" the value of this, just pass in the correct value to apply, depending on how you would call it "normally":

func.apply(undefined, []); // global object, or undefined in ES5 strict mode
obj.func.apply(obj, []);

Solution 4:

If you are calling a function alone, pass null.

func.apply(null, ['some', 'arguments']);

If you are calling a function that is a method of an object, pass that object.

var arr = [];
arr.push.apply(arr, ['some', 'arguments']);

In order to match a how this works.