I mentioned that normal calling of a function (i.e. have a function fx, call it via fx()) and calling with the new keyword i.e. (new fx()) are some of the various ways to call a Javascript function and have the this keyword switch context.
There are 3 other ways a Javascript function can be called with the ability to determine what this keyword references. call, apply and bind. To be technically specific: Function.prototype.call, Function.prototype.apply, and Function.prototype.bind.
.call()
.call() allows the calling of a function in a way that this can be specified, while also passing in required arguments, if any, to the function. i.e. having a function fx:
var fx = function (arg1,arg2) {
console.log(this,arg1,arg2);
}
console.log(this,arg1,arg2);
}
and calling it:
fx.call(null, "first params", "second params");
//logs: null, “first params”, “second params”
//and...
fx.call({id : 1, name : "akpos"}, "first params", "second params");
//logs {id : 1, name : "akpos"}, "first params", "second params"
//logs: null, “first params”, “second params”
//and...
fx.call({id : 1, name : "akpos"}, "first params", "second params");
//logs {id : 1, name : "akpos"}, "first params", "second params"
.apply()
.apply() is very similar to .call(), just that it requires you to specify the passed arguments to the function as arrays. That is, still using the previous fx function defined above. we can call it thus:
fx.apply(null, ["first params", "second params"]);
//logs null, "first params", "second params"
//and...
fx.apply({id : 1, name : "akpos"},[ "first params", "second params"]);
//logs {id : 1, name : "akpos"}, "first params", "second params"
//logs null, "first params", "second params"
//and...
fx.apply({id : 1, name : "akpos"},[ "first params", "second params"]);
//logs {id : 1, name : "akpos"}, "first params", "second params"
as you can see, .call() and .apply() only differ in how they handle function arguments.
.bind()
.bind() is quite different from .call() and .apply(). It also allows you to determine what the value of this would be, but it does not call the function but returns an exact copy of the function but with the specified this bound appropriately.Still using the fx function defined, we use .bind() to create a new function fxbound which has the this referencing the value specified in .bind()
var fxbound = fx.bind(null, "first params", "second params");
fxbound();
//logs null, "first params", "second params"
var fxbound = fx.bind({id : 1, name : "akpos"}, "first params", "second params")
fxbound();
//logs {id : 1, name : "akpos"}, "first params", "second params"
fxbound();
//logs null, "first params", "second params"
var fxbound = fx.bind({id : 1, name : "akpos"}, "first params", "second params")
fxbound();
//logs {id : 1, name : "akpos"}, "first params", "second params"
.call(), apply(), bind(), is obvious, makes it easier to write generic function which can be called on different objects;
A trivial illustration:
var shoppingCart = (function(){
var _calculatePrice = function () {
return this.price * this.amount;
};
return {
calculatePrice : _calculatePrice
}
})();
var goods = {
name : ‘hammer’,
price: 199,
amount : 2
};
shoppingCart.calculatePrice.call(goods);
var _calculatePrice = function () {
return this.price * this.amount;
};
return {
calculatePrice : _calculatePrice
}
})();
var goods = {
name : ‘hammer’,
price: 199,
amount : 2
};
shoppingCart.calculatePrice.call(goods);
in the definition of _calculatePrice that is revealed via calculatePrice, you have this, whose value is then made the goods object at the point of calling it.
There are varied scenarios where applying this pattern comes in handy.
I thus like to have a mental model in which I think of a function that has this in its definition as a generic construct I can pass in different objects (with expected properties) in, and have it operated on.
Great! Here is another simple example the difference between call() and apply()
ReplyDeletethis is the best example on internet that demonstrate the point clear and simple.
ReplyDeleteIt doesn't assume you are a retard, and then doesn't go on and on forever without telling the main thing.
This helped me where SO, and javascriptissexy failed.
SIMPLY AWESOME EXPLANATION!!!!
ReplyDeleteGood example
ReplyDelete