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.
Related
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.
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.
Here's the problem (called "Compose functions (T Combinator)" on codewars.com, in case you want to try it out in the original environment):
Let's make a function called compose that accepts a value as a parameter, as well as any number of functions as additional parameters.
The function will return the value that results from the first parameter being used as a parameter for all of the accepted function parameters in turn. If only a single parameter is passed in, return that parameter.
So:
var doubleTheValue = function(val) { return val * 2; }
var addOneToTheValue = function(val) { return val + 1; }
compose(5, doubleTheValue) // should === 10
compose(5, doubleTheValue, addOneToTheValue) // should === 11
Here was one of the possible solutions:
var compose = function(initialValue) {
var functions = Array.prototype.slice.call(arguments, 1);
return functions.reduce(function(previousResult, func){
return func.call(this, previousResult);
}, initialValue);
}
Why do we need to return func.call(this, previousResult) rather than just func(previousResult)? The latter only works in some cases. What will "this" default to without the call?
Why do we need to return func.call(this, previousResult) rather than just func(previousResult)?
We don't really. this is not the this value of the compose function (what the author probably intended), but of the reduce callback - where it is specified to be undefined.
What will "this" default to without the call?
undefined as well, see Why is "this" in an anonymous function undefined when using strict?.
In strict mode, this will be undefined since there is no calling context.
In non-strict Javascript it will be the global object (window in a browser).
Why do we need to return func.call(this, previousResult) rather than just func(previousResult)?
this defaults to our window.
Basically, we're giving it a secondary value in order to further our progression down the line.
If you were to call simply previousResult, the JS doesn't know where to look to find such a thing. Your are referencing the window if you don't call a prior parameter. This is very common in most OOP languages. You can't look for your value IN window without further defining that you want something IN window.
Essentially, we are just providing a bogus variable in order to get to the next step in the chain. You will see this a lot with Python and Ruby code.
The reason you set this is because this will equal the parent window, then you know you can find the next variable within that particular parameter.
Simple Example:
It's sort of like trying to call a variable in a different function. Just doesn't work without defining your scope first.
function foo(){
console.log('foo', this);
}
foo();
foo.call({ bar: 1 });
foo.apply([{ bar: 1 }]);
Is there any way to know if foo() was called using a normal invoke or call/apply?
http://jsfiddle.net/H4Awm/1/
No. You can't detect if a function is called from call/apply or normally.
They're not magical beings, all they do is set the arguments and this value. There is a subtle difference when it comes to undefined/undeclared values but that's it.
All .apply and .call do in ES5 is:
Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and argList as the list of arguments.
It sets the internal caller attribute correctly so something naive like this would not work.
Unless you redefine Function.prototype.call and Function.prototype.apply (and pass another argument to your function), there is no way of doing so - the actual internal mechanics (the [[Call]] internal function) do not provide any method of signalling that it is called using ().
Compare the specification for a general function call and for Function.prototype.apply - each call the internal code of the function in exactly the same manner, and there is no external property set that is able to give you whether is called using that or not.
See the specification for the internal function [[Call]]:
13.2.1 [[Call]]
When the [[Call]] internal method for a Function object F is called with a this value and a list of arguments, the following steps are taken:
Let funcCtx be the result of establishing a new execution context for function code using the value of F's [[FormalParameters]] internal property, the passed arguments List args, and the this value as described in 10.4.3.
Let result be the result of evaluating the FunctionBody that is the value of F's [[Code]] internal property. If F does not have a [[Code]] internal property or if its value is an empty FunctionBody, then result is (normal, undefined, empty).
Exit the execution context funcCtx, restoring the previous execution context.
If result.type is throw then throw result.value.
If result.type is return then return result.value.
Otherwise result.type must be normal. Return undefined.
There is no provision to change the running of a function from whether it is called using call/apply or not - the only thing that changes what it does are the arguments for the function itself and what is this meant to be within the function.
I hope this solve your problem:
function foo(){
console.log('foo', this);
if (typeof this.length === "number") {
//function has been apply
} else {
//function has been call
}
}
foo();
foo.call({ bar: 1 });
foo.apply([{ bar: 1 }]);
Try something like this:
function foo(){
console.log('foo', this);
console.log( arguments );
}
Function.prototype._apply = Function.prototype.apply;
Function.prototype.apply = function(ths,args){
args.unshift('apply');
this._apply(ths,args);
};
foo();
foo.call(this, { bar: 1 });
foo.apply(this, [{ bar: 1 }]);
Dirty, dirty hack:
function foo() {
var isNatural = !/foo\.(call|apply)/.test("" + foo.caller)
console.log(isNatural ? "foo()" : "foo.{call,apply}()")
}
function caller1() {
foo()
}
function caller2() {
foo.call(null, { bar: 1 })
}
function caller3() {
foo.apply(null, [{ bar: 1 }])
}
caller1()
caller2()
caller3()
It's just food for thought. Don't use it on production.
I can't think of a reason you should be checking for this but, you could check by comparing this === window, as that's the default scope (assuming browser based Javascript), but this could be faked by simply calling foo like so foo.call(window) which is basically what calling foo() is doing normally.
This also probably won't work using window for functions that are properties of other objects or prototypes.
Had a question about the 'duck punching' pattern I first encountered on Paul Irish's blog. I get the general premise... save a ref to an existing function, then replace the existing function with a conditional branch that will call a new function if condition is met, or the old version if not. My question is why do we have to use the "apply" with 'this' as the first param when we call the _old function? I understand how apply works, but I'm looking for some clarification on why it is necessary.
(function($){
// store original reference to the method
var _old = $.fn.method;
$.fn.method = function(arg1,arg2){
if ( ... condition ... ) {
return ....
} else { // do the default
return _old.apply(this,arguments);
}
};
})(jQuery);
Consider this example
var obj = {
foo: "bar",
baz: function () {
return this.foo;
}
};
o = obj.baz;
obj.baz(); // "bar"
o(); // undefined
if you call a method with obj.baz, the object that is behind the dot is the function's context (this will refer to this object).
if you store a method in a variable, you lose the information about the context. In that case, the context will be set to the global object.
var obj = {
baz: function () {
return this;
}
};
o = obj.baz;
obj.baz() === obj; // true
o() === obj; // false
o() === window; // true
A proper context will likely be important for the .method to work as intended.
You pass this because apply() needs the first argument to be what this should be when calling the old function.
apply() is being used so you can easily hand arguments which will be treated as the arguments to the old function.
So, when deciding what to pass as this, you have chosen to pass on what this is in that context.
If you were to call the original function without apply, you let JavaScript decide what to bind this to, and that may well be something different from what it would be bound to if you hadn't monkeypatched/duckpunched the original code.
Using apply, you ensure that the correct value is used for this, e.g. the one the wrapper function is being called with.