From the MDN:
The bind() method creates a new function that, when called, has its this keyword set to the provided value
And I can happily see it working in this example:
(function () {
console.log(this);
}).bind({foo:"bar"})();
which logs Object { foo="bar"}.
But if I chain another bind call, or even a "call" call, I'm still getting the function invoked with "this" assigned to the object passed to the first bind. Examples:
(function () {
console.log(this);
}).bind({foo:"bar"}).bind({oof:"rab"})();
&
(function () {
console.log(this);
}).bind({foo:"bar"}).call({oof:"rab"});
Both log Object { foo="bar"} instead of what I would expect: Object { oof="rab"}.
No matter how many bind calls I chain, only the first one seems to have an effect.
Why?
This might help. I just found out jQuery's version is behaving the same way! :O
jQuery.proxy(
jQuery.proxy(function() {
console.log(this);
},{foo:"bar"})
,{oof:"rab"})();
logs Object { foo="bar"}
It is tempting to think of bind as somehow modifying a function to use a new this. In this (incorrect) interpretation, people think of bind as adding some kind of magic flag to the function telling it to use a different this next time it's called. If that were the case, then it should be possible to "override" and change the magic flag. And one would then ask, what is the reason for arbitrarily restricting the ability to do so?
But in fact, that's not how it works. bind creates and returns a new function which when called invokes the first function with a particular this. The behavior of this newly created function, to use the specified this to call the original function, is burned in when the function is created. It cannot be changed any more than the internals of any other function returned by a function could be changed after the fact.
It may help to look at a real simple implementation of bind:
// NOT the real bind; just an example
Function.prototype.bind = function(ctxt) {
var fn = this;
return function bound_fn() {
return fn.apply(ctxt, arguments);
};
}
my_bound_fn = original_fn.bind(obj);
As you can see, nowhere in bound_fn, the function returned from bind, does it refer to the this with which the bound function was called. It's ignored, so that
my_bound_fn.call(999, arg) // 999 is ignored
or
obj = { fn: function () { console.log(this); } };
obj.fn = obj.fn.bind(other_obj);
obj.fn(); // outputs other_obj; obj is ignored
So I can bind the function returned from bind "again", but that is not rebinding the original function; it's merely binding the outer function, which has no effect on the inner function, since it is already set up to call the underlying function with the context (this value) passed to bind. I can bind again and again but all I end up doing is creating more outer functions which may be bound to something but still end up calling the innermost function returned from the first bind.
Therefore, it is somewhat misleading to say that bind "cannot be overridden".
If I want to "rebind" a function, then I can just do a new binding on the original function. So if I've bound it once:
function orig() { }
my_bound_fn = orig.bind(my_obj);
and then I want to arrange for my original function to be called with some other this, then I don't rebind the bound function:
my_bound_fn = my_bound_fn.bind(my_other_obj); // No effect
Instead, I just create a new function bound to the original one:
my_other_bound_fn = orig.bind(my_other_obj);
I found this line on MDN:
The bind() function creates a new function (a bound function) with the
same function body (internal call property in ECMAScript 5 terms) as
the function it is being called on (the bound function's target
function) with the this value bound to the first argument of bind(),
which cannot be overridden.
so maybe it's really cannot be overridden once it is set.
torazaburo's excellent answer gave me an idea. It would be possible for a bind-like function, instead of baking the receiver (this) into the call inside a closure, to put it as a property on the function object and then use it when the call is made. That would allow a rebind to update the property before the call is made, effectively giving the rebind results that you expected.
For example,
function original_fn() {
document.writeln(JSON.stringify(this));
}
Function.prototype.rebind = function(obj) {
var fn = this;
var bound = function func() {
fn.call(func.receiver, arguments);
};
bound.receiver = obj;
bound.rebind = function(obj) {
this.receiver = obj;
return this;
};
return bound;
}
var bound_fn = original_fn.rebind({foo: 'bar'});
bound_fn();
var rebound_fn = bound_fn.rebind({fred: 'barney'});
rebound_fn();
Or, the output from node.js is as follows.
{ foo: 'bar' }
{ fred: 'barney' }
Note that the first call to rebind is calling the one that was added to Function.prototype since it is being called on ordinary function original_fn, but the second call is calling the rebind that was added as a property to the bound function (and any subsequent calls will call this one, as well). That rebind simply updates receiver and returns the same function object.
It was possible to access the receiver property within the bound function by making it a named function expression.
Okay, this is going to be mostly speculation but I'll try and reason through it.
The ECMAScript specification (which is currently down) states the following for the bind function (emphasis my own):
15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, …]])
The bind method takes one or more arguments, thisArg and (optionally)
arg1, arg2, etc, and returns a new function object by performing the
following steps:
Let Target be the this value.
If IsCallable(Target) is false, throw a TypeError exception.
Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
Let F be a new native ECMAScript object .
Set all the internal methods, except for [[Get]], of F as specified in 8.12.
Set the [[Get]] internal property of F as specified in 15.3.5.4.
Set the [[TargetFunction]] internal property of F to Target.
Set the [[BoundThis]] internal property of F to the value of thisArg.
Set the [[BoundArgs]] internal property of F to A.
Set the [[Class]] internal property of F to "Function".
Set the [[Prototype]] internal property of F to the standard built-in Function prototype object as specified in
15.3.3.1.
Set the [[Call]] internal property of F as described in 15.3.4.5.1.
Set the [[Construct]] internal property of F as described in 15.3.4.5.2.
Set the [[HasInstance]] internal property of F as described in 15.3.4.5.3.
If the [[Class]] internal property of Target is "Function", then a. Let L be the length property of Target minus the length of A. b.
Set the length own property of F to either 0 or L, whichever is
larger.
Else set the length own property of F to 0.
Set the attributes of the length own property of F to the values specified in 15.3.5.1.
Set the [[Extensible]] internal property of F to true.
Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
Call the [[DefineOwnProperty]] internal method of F with arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower,
[[Enumerable]]: false, [[Configurable]]: false}, and false.
Call the [[DefineOwnProperty]] internal method of F with arguments "arguments", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower,
[[Enumerable]]: false, [[Configurable]]: false}, and false.
Return F
And when you call a function on your Object that was created with bind:
15.3.4.5.1 [[Call]]
When the [[Call]] internal method of a function object, F, which was created using the bind function is called with a
this value and a list of arguments ExtraArgs, the following steps are
taken:
Let boundArgs be the value of F’s [[BoundArgs]] internal property.
Let boundThis be the value of F’s [[BoundThis]] internal property.
Let target be the value of F’s [[TargetFunction]] internal property.
Let args be a new list containing the same values as the list boundArgs in the same order followed by the same values as the list
ExtraArgs in the same order.
Return the result of calling the [[Call]] internal method of target providing boundThis as the this value and providing args as the
arguments
Call specifies how every function is called. And somewhat resembles the JavaScript call:
someFunction.[[call]](thisValue, arguments) {
}
However when [[call]] is used on a bound function, the thisValue is overridden with the value of [[BoundThis]]. In the case of calling bind a second time, the thisValue that you attempt to override the first with is replaced by [[BoundThis]], essentially incurring no effect whatsoever on the value of thisValue:
boundFunction.[[call]](thisValue, arguments) {
thisValue = boundFunction.[[BoundThis]];
}
You'll notice that if you try and use call or apply then they will also have no effect because their attempt to override the thisValue property will be reversed when [[call]] invokes the next function.
These simplified examples of how bind() works explain it better.
Here is what function bound once looks like:
function bound_function() {
function original_function() {
console.log(self);
}
var self = 1;
original_function();
}
bound_function()
Here is what happens if we wrap original function twice:
function bound_function2() {
function bound_function1() {
function original_function() {
console.log(self);
}
var self = 1;
original_function();
}
var self = 2;
bound_function1();
}
bound_function2()
I think the way to think about it is: When you call bind() the first time the value of 'this' inside the function returned by the call to bind() is FIXED, to the given value. That is possible BECAUSE it wasn't fixed before, it was unbound. But once it is fixed it can not be fixed to anything else because it is no longer unfixed, it is no longer a "variable".
In theory there could be an opposite operation to bind called "unbind" which you could call like:
myFunk.bind(something)
.unbind(); // -> has same behavior as original myFunk
The name "bind" indicates that the (pseudo-) variable 'this' is BOUND to something, it is not simply ASSIGNED a value, which could then be assigned again and again.
When something is "bound" it has a value and that value can not be replaced --because it is "bound". So you would need an unbind() operation to make that possible. But since you assumably have the original function around somewhere
there is no need for "unbind" really.
I agree this behavior is perhaps surprising and unexpected and thus possibly error-prone because if you get a function as argument there seems to be no way to tell whether your bind() on it has any effect or not.
HOWEVER if you don't know much about such function-argument it would also be impossible to know what kind of value you CAN bind to it without breaking the calls it makes to 'this' inside it.
SO the bind() operation itself is rather hazardous. Re-binding would be doubly hazardous. So you are best off trying to avoid doing that if possible.
Related
I'm writing a function that needs to take an object and call a method on that object. I'm having trouble wrapping my head around how this is set when invoking a function.
Let's say I have this object:
myObj = {
x: 2,
get: function() {
return this.x;
}
};
If I simply do:
callbackEval = function(fn) {
return fn();
};
and then invoke it as
callbackEval(myObj.get)
This returns undefined, since this isn't bound. Obviously if I write this as
callbackEval(function() {
return myObj.get()
});
then it returns 2, as I'd expect.
But if, instead of passing a callback, I pass a property name, look up that property, and then call that function, I get mixed results.
Let's say I write these variants:
propEval = function(obj, fnName) {
const fn = obj[fnName];
return fn();
}
propEval2 = function(obj, fnName) {
return obj[fnName]();
}
propEval3 = function(obj, fnName) {
return (obj[fnName])()
}
propEval4 = function(obj, fnName) {
return (obj[fnName] || true)()
}
and call them like so:
propEval(myObj, "get");
propEval2(myObj, "get");
propEval3(myObj, "get");
propEval4(myObj, "get");
then, in order, I get:
undefined
2
2
undefined
What's the difference between how the javascript handles these 4 variations? Why is this bound when we make the calls in propEval2 and propEval3, but not in propEval4?
The partial answer: this is, bluntly put, a function's argument. It's 0-th argument, hidden and passed to it in a special way (or in explicit way - with call and apply). There's also no methods, BTW, just functions that happen to be properties of an object. If you invoke a function this way: foo.bar() (=== foo['bar']()), you implicitly pass to it foo as its this binding. When you invoke it this way: bar(), you do not.
Hence: propEval - no object, no this binding.
propEval2 - the classic example of invoking a so-called "method".
propEval3 - the () are irrelevant here. With or without them, the expression is evaluated the same, with the member access operator and the function call operator having the same precedence.
propEval4 - it looks like the one above, doesn't it? Hah! What it actually does is first, evaluate the expression (obj[fnName] || true), then invokes the result. It might as well be
const someTemporaryVariable = obj[fnName] || true;
return someTemporaryVariable();
I think.
propEval1 when you call function myObj.get, myObj is being passed in as the 'this' context. When you call fn you're calling the function without a context thus using the enclosing context. Note context being supplied is determined by where the function is being called and whether theres a . or not.
propEval2 and propEval3 are the same (parens don't matter) since you're always calling the function as a property of myObj. myObj.get is the same as myObj['get'].
propEval4 I haven't seen this one but it seems that with the || it evaluates the condition and then executes the return of the condition which will be a reference to the function resulting in something similar to propEval1.
From the MDN:
The bind() method creates a new function that, when called, has its this keyword set to the provided value
And I can happily see it working in this example:
(function () {
console.log(this);
}).bind({foo:"bar"})();
which logs Object { foo="bar"}.
But if I chain another bind call, or even a "call" call, I'm still getting the function invoked with "this" assigned to the object passed to the first bind. Examples:
(function () {
console.log(this);
}).bind({foo:"bar"}).bind({oof:"rab"})();
&
(function () {
console.log(this);
}).bind({foo:"bar"}).call({oof:"rab"});
Both log Object { foo="bar"} instead of what I would expect: Object { oof="rab"}.
No matter how many bind calls I chain, only the first one seems to have an effect.
Why?
This might help. I just found out jQuery's version is behaving the same way! :O
jQuery.proxy(
jQuery.proxy(function() {
console.log(this);
},{foo:"bar"})
,{oof:"rab"})();
logs Object { foo="bar"}
It is tempting to think of bind as somehow modifying a function to use a new this. In this (incorrect) interpretation, people think of bind as adding some kind of magic flag to the function telling it to use a different this next time it's called. If that were the case, then it should be possible to "override" and change the magic flag. And one would then ask, what is the reason for arbitrarily restricting the ability to do so?
But in fact, that's not how it works. bind creates and returns a new function which when called invokes the first function with a particular this. The behavior of this newly created function, to use the specified this to call the original function, is burned in when the function is created. It cannot be changed any more than the internals of any other function returned by a function could be changed after the fact.
It may help to look at a real simple implementation of bind:
// NOT the real bind; just an example
Function.prototype.bind = function(ctxt) {
var fn = this;
return function bound_fn() {
return fn.apply(ctxt, arguments);
};
}
my_bound_fn = original_fn.bind(obj);
As you can see, nowhere in bound_fn, the function returned from bind, does it refer to the this with which the bound function was called. It's ignored, so that
my_bound_fn.call(999, arg) // 999 is ignored
or
obj = { fn: function () { console.log(this); } };
obj.fn = obj.fn.bind(other_obj);
obj.fn(); // outputs other_obj; obj is ignored
So I can bind the function returned from bind "again", but that is not rebinding the original function; it's merely binding the outer function, which has no effect on the inner function, since it is already set up to call the underlying function with the context (this value) passed to bind. I can bind again and again but all I end up doing is creating more outer functions which may be bound to something but still end up calling the innermost function returned from the first bind.
Therefore, it is somewhat misleading to say that bind "cannot be overridden".
If I want to "rebind" a function, then I can just do a new binding on the original function. So if I've bound it once:
function orig() { }
my_bound_fn = orig.bind(my_obj);
and then I want to arrange for my original function to be called with some other this, then I don't rebind the bound function:
my_bound_fn = my_bound_fn.bind(my_other_obj); // No effect
Instead, I just create a new function bound to the original one:
my_other_bound_fn = orig.bind(my_other_obj);
I found this line on MDN:
The bind() function creates a new function (a bound function) with the
same function body (internal call property in ECMAScript 5 terms) as
the function it is being called on (the bound function's target
function) with the this value bound to the first argument of bind(),
which cannot be overridden.
so maybe it's really cannot be overridden once it is set.
torazaburo's excellent answer gave me an idea. It would be possible for a bind-like function, instead of baking the receiver (this) into the call inside a closure, to put it as a property on the function object and then use it when the call is made. That would allow a rebind to update the property before the call is made, effectively giving the rebind results that you expected.
For example,
function original_fn() {
document.writeln(JSON.stringify(this));
}
Function.prototype.rebind = function(obj) {
var fn = this;
var bound = function func() {
fn.call(func.receiver, arguments);
};
bound.receiver = obj;
bound.rebind = function(obj) {
this.receiver = obj;
return this;
};
return bound;
}
var bound_fn = original_fn.rebind({foo: 'bar'});
bound_fn();
var rebound_fn = bound_fn.rebind({fred: 'barney'});
rebound_fn();
Or, the output from node.js is as follows.
{ foo: 'bar' }
{ fred: 'barney' }
Note that the first call to rebind is calling the one that was added to Function.prototype since it is being called on ordinary function original_fn, but the second call is calling the rebind that was added as a property to the bound function (and any subsequent calls will call this one, as well). That rebind simply updates receiver and returns the same function object.
It was possible to access the receiver property within the bound function by making it a named function expression.
Okay, this is going to be mostly speculation but I'll try and reason through it.
The ECMAScript specification (which is currently down) states the following for the bind function (emphasis my own):
15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, …]])
The bind method takes one or more arguments, thisArg and (optionally)
arg1, arg2, etc, and returns a new function object by performing the
following steps:
Let Target be the this value.
If IsCallable(Target) is false, throw a TypeError exception.
Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
Let F be a new native ECMAScript object .
Set all the internal methods, except for [[Get]], of F as specified in 8.12.
Set the [[Get]] internal property of F as specified in 15.3.5.4.
Set the [[TargetFunction]] internal property of F to Target.
Set the [[BoundThis]] internal property of F to the value of thisArg.
Set the [[BoundArgs]] internal property of F to A.
Set the [[Class]] internal property of F to "Function".
Set the [[Prototype]] internal property of F to the standard built-in Function prototype object as specified in
15.3.3.1.
Set the [[Call]] internal property of F as described in 15.3.4.5.1.
Set the [[Construct]] internal property of F as described in 15.3.4.5.2.
Set the [[HasInstance]] internal property of F as described in 15.3.4.5.3.
If the [[Class]] internal property of Target is "Function", then a. Let L be the length property of Target minus the length of A. b.
Set the length own property of F to either 0 or L, whichever is
larger.
Else set the length own property of F to 0.
Set the attributes of the length own property of F to the values specified in 15.3.5.1.
Set the [[Extensible]] internal property of F to true.
Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
Call the [[DefineOwnProperty]] internal method of F with arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower,
[[Enumerable]]: false, [[Configurable]]: false}, and false.
Call the [[DefineOwnProperty]] internal method of F with arguments "arguments", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower,
[[Enumerable]]: false, [[Configurable]]: false}, and false.
Return F
And when you call a function on your Object that was created with bind:
15.3.4.5.1 [[Call]]
When the [[Call]] internal method of a function object, F, which was created using the bind function is called with a
this value and a list of arguments ExtraArgs, the following steps are
taken:
Let boundArgs be the value of F’s [[BoundArgs]] internal property.
Let boundThis be the value of F’s [[BoundThis]] internal property.
Let target be the value of F’s [[TargetFunction]] internal property.
Let args be a new list containing the same values as the list boundArgs in the same order followed by the same values as the list
ExtraArgs in the same order.
Return the result of calling the [[Call]] internal method of target providing boundThis as the this value and providing args as the
arguments
Call specifies how every function is called. And somewhat resembles the JavaScript call:
someFunction.[[call]](thisValue, arguments) {
}
However when [[call]] is used on a bound function, the thisValue is overridden with the value of [[BoundThis]]. In the case of calling bind a second time, the thisValue that you attempt to override the first with is replaced by [[BoundThis]], essentially incurring no effect whatsoever on the value of thisValue:
boundFunction.[[call]](thisValue, arguments) {
thisValue = boundFunction.[[BoundThis]];
}
You'll notice that if you try and use call or apply then they will also have no effect because their attempt to override the thisValue property will be reversed when [[call]] invokes the next function.
These simplified examples of how bind() works explain it better.
Here is what function bound once looks like:
function bound_function() {
function original_function() {
console.log(self);
}
var self = 1;
original_function();
}
bound_function()
Here is what happens if we wrap original function twice:
function bound_function2() {
function bound_function1() {
function original_function() {
console.log(self);
}
var self = 1;
original_function();
}
var self = 2;
bound_function1();
}
bound_function2()
I think the way to think about it is: When you call bind() the first time the value of 'this' inside the function returned by the call to bind() is FIXED, to the given value. That is possible BECAUSE it wasn't fixed before, it was unbound. But once it is fixed it can not be fixed to anything else because it is no longer unfixed, it is no longer a "variable".
In theory there could be an opposite operation to bind called "unbind" which you could call like:
myFunk.bind(something)
.unbind(); // -> has same behavior as original myFunk
The name "bind" indicates that the (pseudo-) variable 'this' is BOUND to something, it is not simply ASSIGNED a value, which could then be assigned again and again.
When something is "bound" it has a value and that value can not be replaced --because it is "bound". So you would need an unbind() operation to make that possible. But since you assumably have the original function around somewhere
there is no need for "unbind" really.
I agree this behavior is perhaps surprising and unexpected and thus possibly error-prone because if you get a function as argument there seems to be no way to tell whether your bind() on it has any effect or not.
HOWEVER if you don't know much about such function-argument it would also be impossible to know what kind of value you CAN bind to it without breaking the calls it makes to 'this' inside it.
SO the bind() operation itself is rather hazardous. Re-binding would be doubly hazardous. So you are best off trying to avoid doing that if possible.
According to this JavaScript reference:
The value null is a JavaScript literal representing null or an "empty"
value, i.e. no object value is present. It is one of JavaScript's
primitive values.
function getMax(arr){
return Math.max.apply(null, arr);
}
Wouldn't explicitly passing the keyword this be clearer, or at least more readable? Then again, at this point I may not understand why you would use null.
Why would you pass 'null' to 'apply' or 'call'?
When there is no value you wish to specify for the this pointer inside the function and the function you're calling is not expecting a particular this value in order to function properly.
Wouldn't explicitly passing the keyword this be clearer? Or at least
more human readable. Then again at this point I may not understand why
you would use null.
In your specific case, probably the best thing to pass is the Math object:
function getMax(arr){
return Math.max.apply(Math, arr);
}
While it turns out that it doesn't matter what you pass as the first argument for Math.max.apply(...) (only because of the implementation specifics of Math.max()), passing Math sets the this pointer to the exact same thing that it would be set to when calling it normally like Math.max(1,2,3) so that is the safest option since you are best simulating a normal call to Math.max().
Why would you pass 'null' to 'apply' or 'call'?
Here are some more details... When using .call() or .apply(), null can be passed when you have no specific value that you want to set the this pointer to and you know that the function you are calling is not expecting this to have any specific value (e.g. it does not use this in its implementation).
Note: Using null with .apply() or .call() is only usually done with functions that are methods for namespace reasons only, not for object-oriented reasons. In other words, the function max() is a method on the Math object only because of namespacing reasons, not because the Math object has instance data that the method .max() needs to access.
If you were doing it this way:
function foo() {
this.multiplier = 1;
}
foo.prototype.setMultiplier = function(val) {
this.multiplier = val;
}
foo.prototype.weightNumbers = function() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += (arguments[i] * this.multiplier);
}
return sum / arguments.length;
}
var x = new foo();
x.setMultiplier(3);
var numbers = [1, 2, 3]
console.log(x.weightNumbers.apply(x, numbers));
When the method you are calling .apply() on needs to access instance data, then you MUST pass the appropriate object as the first argument so that the method has the right this pointer to do its job as expected.
Calling apply with null as the first argument is like calling the function without providing any object for the this.
What does the apply method do?
The apply() method calls a function with a given this value and
arguments provided as an array (or an array-like object).
fun.apply(thisArg, [argsArray])
thisArg
The value of this provided for the call to fun. Note that this may not
be the actual value seen by the method: if the method is a function in
non-strict mode code, null and undefined will be replaced with the
global object, and primitive values will be boxed.
Further documentation can be found here.
One case where I have found this useful is when the function I'm calling is already bound to a particular context.
Because bound functions cannot be rebound, and they will always be called with the thisArg that was passed into bind, there is no use in passing a thisArg into call or apply. From source:
The bind() function creates a new bound function (BF).... When bound function is called, it calls internal method [[Call]] on [[BoundTargetFunction]], with following arguments Call(boundThis, args).
Here's an example:
class C {
constructor() {
this.a = 1;
}
}
function f(n, m) {
console.log(this.a + n + m);
}
let c = new C();
var boundF = f.bind(c, 2); // the context `c` is now bound to f
boundF.apply(null, [3]); // no reason to supply any context, since we know it's going to be `c`
I am bit late to answer this. I will try to give a long descriptive explanation here.
What is null in JavaScript?
The value null is a literal (not a property of the global object like undefined can be). It is one of JavaScript's primitive values.
In APIs, null is often retrieved in place where an object can be expected but no object is relevant.
fun.apply(thisArg, [argsArray])
thisArg: The value of this provided for the call to fun. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode code, null and undefined will be replaced with the global object, and primitive values will be boxed.
argsArray: An array-like object, specifying the arguments with which fun should be called, or null or undefined if no arguments should be provided to the function. Starting with ECMAScript 5 these arguments can be a generic array-like object instead of an array. See below for browser compatibility information.
If you are using 'strict mode', then it is advisable to pass the this or
Math as the parameter.
Apply is useful when you want to pass along the responsibility for doing something to a function that is determined at run time, and pass a variable number of arguments to that function. You may or may not have any appropriate "this" context when you're doing that.
For example I use a library I wrote to facilitate listening for and raising application events that uses apply.
I wanted to be able to be able to raise an event like this:
EventManager.raise('some:event-name', arg1, arg2, arg3, ..);
..and have all of the registered handlers for that event get called with that list of arguments (arg1, arg2, etc). So in the raise function, it goes through the handlers that are registered for that event name and calls them, passing all the passed in arguments except for the event name, like this:
var args = [];
Array.prototype.push.apply(args, arguments);
args.shift();
for (var l in listeners) {
var listener = listeners[l];
listener.callback.apply(listener.context, args);
}
When a registered handler (listener.callback) is called, apply is used to pass along a variable number of arguments. Here I have allowed the listener to supply a this context for its event handler when the listener is defined, but that context might not be defined or it might be null, and that's perfectly fine.
For a long time the raise function didn't even facilitate using any callback context. I eventually came across a need for it, so I put in support for it, but most of the time I don't really need or use it.
If functions are objects, where does the function's body go?
Let me clarify what I am confused about. Functions are objects, okay. I can think of an object as a hash map consisting of string keys and arbitrarily typed values. I can do this:
function Square(size) {
Rectangle.call(this, size, size);
}
Square.prototype = new Rectangle();
I just treated Square like a regular object and messed with its prototype property by assigning a new value to it. However, if functions are just objects (or hash maps for that matter), where is the function's body (in this example Rectangle.call(this, size, size);) being stored?
I figured it must be stored as the value of some property, something like the following maybe:
console.log(Square.executableBody); // "Rectangle.call(this, size, size);"
Obviously, this is not the case. Interestingly, while reading "The Principles of Object-Oriented JavaScript" by Nicholas C. Zakas, I stumbled upon this:
[...] functions are actually objects in JavaScript. The defining characteristic of a function - what distinguishes it from any other object - is the presence of an internal property named [[Call]]. Internal properties are not accessible via code [...] The [[Call]] property is unique to functions and indicates that the object can be executed.
This might be the property I was looking for above. It does not go into detail, though. Is the function's body actually stored within the [[Call]] property? If so, how does execution work? Unfortunately I was unable to find out more about [[Call]], Google mostly came up with information on a function's call method...
Some clarification would be much appreciated! :)
It becomes the value of another internal property, called [[Code]]:
13.2 Creating Function Objects
Given an optional parameter list specified by FormalParameterList, a body specified by FunctionBody, a Lexical Environment specified by Scope, and a Boolean flag Strict, a Function object is constructed as follows:
[...]
Set the [[Code]] internal property of F to FunctionBody.
If so, how does execution work?
Calling a function basically calls the internal [[Call]] method, which is described in http://es5.github.io/#x13.2.1. I guess the important step is:
Let result be the result of evaluating the FunctionBody that is the value of F's [[Code]] internal property.
Basically, for all practical purposes you can consider the function in its entirety to be the object. You can study the JS spec or JS engine source code to learn about how the function body is actually stored in an internal property on the object, but this won't really help you understand how it works as a JS programmer. You can see the body as a string by evaluating fn.toString. You cannot otherwise access the body other than to execute it or bind to it or call other methods on Function.prototype. However, because it's an object, it can also have properties attached to it like any other object.
Why would I want to attach a property to a function? Here is an example of a memoization function (deliberately simplified):
function memoize(fn) {
var cache = {};
function memoized(x) {
return x in cache ? cache[x] : cache[x] = fn(x);
};
memoized.clear = function() { cache = {}; };
return memoized;
}
So we are placing a function clear as a property on the returned function. We can use this as:
memofied = memoize(really_long_calculation);
result = memofied(1); // calls really_long_calculation
result = memofied(1); // uses cached value
memofied.clear(); // clear cache
result = memofied(1); // calls really_long_calculation again
The function is enough of an object that Object.defineProperty can be called on it, allowing us to write the memoization function above as follows, if we really wanted to:
function memoize(fn) {
var cache = {};
return Object.defineProperty(function (x) {
return x in cache ? cache[x] : cache[x] = fn(x);
}, 'clear', {value: function() { cache = {}; } });
}
(since Object.defineProperty returns the object.) This has the advantage that clear takes on the default non-enumerable and non-writeable properties, which seems useful.
I could even use a function as the first (prototype) argument to Object.create:
someobj = Object.create(function() { }, { prop: { value: 1 } });
but there's no way to call the function serving as prototype. However, its properties will be available in the prototype chain of the created object.
"The this keyword always refers to the object that the containing function is a method of."
Great, sounds simple enough, but here's what I'm wondering about...
For example:
function func1() {
function func2() {
alert(this == window); // true
}
func2();
alert(this == window); // true
}
func1.func3 = function () {
alert(this == window); // false
alert(this == func1); // true
};
func1();
func1.func3();
Now, since func1 is actually a method of the global (window) object (a function object assigned to the property func1 of the global object) it makes sense that this inside func1 refers to the global object, and since func3 is a method of func1's function object it makes sense that this inside func3 refers to func1's function object.
The thing that bothers me is func2. I know that this inside a nested function is also supposed to reference the global object, but I'm not sure why since func2 is NOT a method of the global object. As far as I understand (and this is the part I might be completely wrong about) func2 is a method of func1's call (activation / variable) object. Now, if I'm right about this (and I'm not sure that I am) then shouldn't this inside func2 refer to func1's call object instead of the global object?
So, I guess my question would be: Is a nested function a method of the call (activation) object of the function it is nested in, and if so, shouldn't this refer to that call object instead the global object?
The this keyword always refers to the object that the containing function is a method of.
No. Unfortunately, it is not easy as that. The documentation of the this keyword at MDN gives a good overview. It is set to the object when the function is called as a method on it, but there are other possibilies. The default is that this is undefined when it is called without anything special, like you do with func1 and func2. For sloppy (non-strict) mode functions undefined (and null) are not used though, this does point to the global object (window in browsers) for them in that case - what you are observing.
But it could also point to fresh object instances when the function is called as a constructor (with the new keyword), or to an event target (like a DOM element) when used as a handler. Last, but not least, it could be set manually with call, apply or bind…
this has nothing to do with nesting. Nesting function declarations/expressions only affects the scope ("privacy", availability) of variables. While the variable scope of a function never changes, the value of this can be different on every invocation - it is more like an extra argument.
The meaning of the this keyword inside a function depends on the way the function is invoked. There are 4 different function invocation patterns in JavaScript.
function invocation pattern foo()
method invocation pattern o.foo()
constructor invocation pattern new foo
call/apply pattern foo.apply(...) or foo.call(...)
Only in #2 is it the case that this inside the function refers to the object of which the function is a method.
You are invoking func2() with the function invocation pattern. When doing so, this refers to the global object.
As suggested by #Bergi, see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this for more detail on the meaning of this and the different function invocation patterns.
but I'm not sure why since func2 is NOT a method of the global object.
Any thing defined inside a function is local to the scope of that function. So func2 belongs to the local scope of func1 and therefore is not attached to window.
In Javascript, the value of this is generally based on how you call the function. When you call a function without any leading object, this is usually set to the global parent object, which is window.
You can explicitly set the value of this in three ways:
myObj.func(a, b); //this set to myObj implicitly because myObj is the parent
func.call(myObj, a, b); //this set to myObj explicitly; the first argument
//to call sets the value of this for that function
func.apply(myObj, [a, b]); //this set to myObj explicitly; the first argument
//to apply also sets the value of this for that
//function.
this can be a tricky concept. MDN has a good article about this.