"this", "bind" , "apply" and "call"
/**
* lets understand the most notorious and complex topic which always
* ditch even a pro javascript programmer.
* "this", "bind" , "apply" and "call".
*/
/************************** EXAMPLE 1 **************************************/
/************** "this" *******************
* just to distinguish English language word this from js keyword this, I will notate the
* JS keyword this within "this", however you gotta use the keyword in programmes as plain this.
*
* "this" is a JS keyword which notates the current object which invokes the function.
* Please pay attention "object which invokes the function".
*
* "object which invokes the function" is the phrase if you remember, will never get confused.
*
* Also remember, "this" is not associated to an object until it is get called by the object.
* means , JS decides during runtime the value of "this" .
*
* Lets see some example that will clarify the cases "this" used in and its ditches.
*/
/* lets understand the global object window */
/**
* if you know, in browser, there is a global object named "window" to which all functions,
* varaibles defined belongs to as properties of window object.
* The functions and variables I am speaking about are the first level(means not defined inside
* any function or object)
*/
var winVariable = "Rishank";/* this is global variable, hence property to window object like window.winVariable */
/**
* below function is a global function which can be assumed as method to window object
* like window.winFunc ( the variable "winFunc" is the name given to anonymous function assigned to it), thus you may call this function as winFunc() or window.winFunc().
* Now as we said above, the "this" is derived by the system during runtime, thus when the
* below function will run , the system will see that internally the function belongs to window
* object , thus it will bind the "this" to window object.
*/
var winFunc = function () {
var insideFunc = "InsideVar";/* this variable is local to function only not (window) */
console.log(this === window);/* true */
console.log(window.winVariable);/* "Rishank", becuase winVariable is global and thus property of window object */
console.log(this.insideFunc);/* undefined , because insideFunc is local to function only, not defined outside(globally) */
console.log(window.insideFunc);/* undefined , because insideFunc is local to function only, not defined outside(globally) */
};
winFunc();
window.winFunc();//same as above call (winFunc is property (method) of window object)
/**
* Above we have assigned anonymous function to a variable.
* Below we have defined a named function "WithName".
* You may think it like var WithName = function(){....}
* Thus it is clear that this named function will be a property to window object say, window.WithName = function(){..}
* Henc we can say, though it looks like a function to outside, but internally system treat as method declared to window object.
*/
function WithName() {
console.log(this === window);/* true */
console.log(this.winVariable);/* "Rishank" */
console.log(window.winVariable);/* "Rishank" */
}
WithName();
window.WithName();/* same as above call (WithName is property (method) of window object). */
/**
* From Above example it is clear that anything defined globally (a variable or function), is actually a property to window object.
*/
/************************** EXAMPLE 2 **************************************/
/**
* Now lets see a user defined object and will check how it behaves when a property or property(method) is associated with
* it
*/
var simplObj = {
league: "SimpleLeague",
simplMethod: function () {
console.log(this === window);/* false ,because during runtime system finds that simpleMethod is invoked on simplObj which is an object
thus "this" will no longer point to window object. */
console.log(this.league);/* "SimpleLeague", because "this" is pointing to simplObj object during runtime invokation of simplMethod. */
}
}
/* now call the method simplMethod. */
simplObj.simplMethod();
window.simplObj.simplMethod();/* same as above call, because though simplObj is an object, but ultimately it is declared globally and thus
will be a property to window object. */
/**
* Ditchy cases:
* Lets make the above example a bit quirky
* Please read the below explanation(anotatted right to console.log) carefully, if you understand this, "this" will no longer a riddle to solve.
*
* Below definintion to be recited to tongue, because the below coming example will be explained on this definition.
* Definition :
"If a function is not a property method of any object or not invoked on any object using dot(.) notation,
it belongs to global object which is a window object(as we saw above in "EXAMPLE 1")".
*/
var simplObjQuirky = {
leagueQuirky: "SimpleLeagueQuirky",
simplObjQuirky: function () {
console.log(this.leagueQuirky);/* SimpleLeagueQuirky, during runtime system finds simplObjQuirky invoked by simplObjQuirky object
hence "this" belongs to simplObjQuirky or this===simplObjQuirky. */
/**
* below InsideFunction call is a catchy one
*/
function InsideFunction() {
console.log(this === window);/**
true, why , lets see:
The best way to remeber this or such cases is:
Here you can see that , though during runtime , system is binding the "this" object to simplObjQuirky
but InsideFunction is not defined directly to simplObjQuirky as property method. We can see its an internal function
defined and called inside the property method simplObjQuirky. Also as I defined in above Definition
InsideFunction is not an immediate property method to simplObjQuirky nor it is invoked using any dot(.) notation
Thus as per the EXAMPLE 1 , it belongs as a property to internal window object .
Hence the reason why "this" is equivalent to "window" object in InsideFunction, becuase "window" is actually calling the
InsideFunction
*/
console.log(this.leagueQuirky);/* undefined, simple "this" belongs to "window" object and no such property exists on "window"(here "this") object. */
}
InsideFunction();
}
};
simplObjQuirky.simplObjQuirky();
/************************** EXAMPLE 3 **************************************/
/**
* lets see a more complex scenario where an anonymous function is getting passed as a parameter(callback function) to a function(method),
* then what will be the "this" object inside that passed anonymous function.
*/
var complxObj = {
complxLeague: "ComplexLeague",
complxMethod: function (callbckFunc) {
console.log(this.complxLeague);/* ComplexLeague */
callbckFunc();/* calling the function passed as parameter to "callbckFunc".
The "callbckFunc" parameter can be think of receiving variable holding reference to anonymous function:
like callbckFunc = function(){.........}, thus calling callbckFunc() is actaully calling the anonymous function.
So if we see it carefully we can easily guess its same case as InsideFunction call described in "EXAMPLE 2".
Thus when the callbckFunc gets called, it is actually getting called inside the method call "complxMethod",
but the "this" object which is getting set inside "callbckFunc" is not the "complxObj" on which "complxMethod" get called.
becuase "callbckFunc" just hold refernce to anonymous function and based on Definition given in "EXAMPLE 2", "callbckFunc"
is not a property of "complxObj" nor called using dot(.) notation.
*/
}
};
/*below method call, we are passing an anonymous function as a parameter to complxObj.complxMethod
*/
complxObj.complxMethod(function () {
console.log("I am a callback function passed as parameter to complxMethod ");
console.log(this === window);/* true */
});
/************************** EXAMPLE 4 **************************************/
/**
* lets see a more complex scenario where a method of an object got assigned to a variable declared globally
*/
var assignObj = {
assignLeague: "AssignLeague",
assignMethod: function (callbckFunc) {
console.log(this.assignLeague);/* undefined ,becuase the method assignMethod of assignObj has assigned
to goblReceiverVar which just hold the refernce to the assignMethod method definition i.e,
function(callbckFunc){....}.
Now during runtime when goblReceiverVar(function(){...}) will execute, the runtime sytem will see that
goblReceiverVar is a property method to "window" object , think like:
window.goblReceiverVar = function(callbckFunc){.....}, thus the system will bind the "this" object to
"window" object, but window object("this") has not such property defined as assignLeague, hence undefined.
*/
callbckFunc();/* the "this" object which is getting set inside callbckFunc is not the assignObj becuase the assignMethod has already became a method of window object.
also callbckFunc just hold refernce to anonymous function and based on Definition given in "EXAMPLE 2", callbckFunc is now a property of window object only.
*/
}
};
var goblReceiverVar = assignObj.assignMethod;
goblReceiverVar(function () {
console.log("I am a callback function passed as parameter to complxMethod method");
console.log(this === window);/* true */
});
/************************** EXAMPLE 5 **************************************/
/**
* lets see a more complex scenario where a method of an object got assigned to a method property belongs to other object.
*/
var custmObj1 = {
league: "CustmObj1 League",
custmObj1Method: function () {
console.log(this.league);
}
};
var custmObj2 = {
league: "CustmObj2 League",
custmObj2Method: null /* no definition */
};
custmObj2.custmObj2Method = custmObj1.custmObj1Method;/* in this we are assigning the method refernce hold by custmObj1.custmObj1Method
to custmObj2.custmObj2Method, although earlier this method was having no function refernce defined of its own, now its holding
reference of custmObj2.custmObj2Method.
*/
custmObj2.custmObj2Method();/* "CustmObj2 League" ,
Reason : because now custmObj2.custmObj2Method holds reference of function definition of custmObj1.custmObj1Method, so
system see it now having a function reference , thus during runtime when system is making a call to custmObj2.custmObj2Method();
it binds the "this" to custmObj2 and execute the function reference it holds in the context of custmObj2,
thus console.log(this.league); will print "CustmObj2 League".This concept is called "Borrowing the method".
*/
/*One thing to remember, even if we assign the method of an object to a variable or property method of another object
it is the method refernce actually getting passed and if any "this" object used inside the method reference body, it will be set to an object invoking it during runtime by the system*/
/************************** EXAMPLE 6 Bind, Call and Apply**************************************/
/************Bind*****************
* With bind we can explicity bound an object to the "this" object defined in borrowed method.
*
* In EXAMPLE 5 we saw borrowing of method.
* Borrowing of method means, to call a method declared on some object by an object for which the method
* doesn't exixts.
*/
var objectWithMethod = {
name: "Object With Method",
objMethod: function () {
console.log(this.name);
}
};
var objectWithoutMethod = {
/* object which dont have any method */
name: "Object WithOut Method"
};
/* now it is to be noticed that both object have one thing in common that both possess the same
property called "name", thus a common method can be used to print the name property of both objects
,how to do that ? is by borrowing a method ,but as we saw in EXAMPLE 5 both objects were had their method property,
one with null reference while one with method property with function reference.
So how to borrow a method without creating method property on objectWithoutMethod.
Well there is a concept introduced in ES5 called "bind".
With bind we can explicity bound an object to the "this" object defined in borrowed method.
*/
var functionWithObjectBound = objectWithMethod.objMethod.bind(objectWithoutMethod);
functionWithObjectBound();/*will print "Object WithOut Method" */
/* how does the above line worked? you can think like :
the part objectWithMethod.objMethod will get the function reference hold by objectWithMethod.objMethod
and then the .bind(objectWithoutMethod) will replace the each "this" occurence under the function refernce
with objectWithoutMethod object, like :
objectWithMethod.objMethod will fetch :
function(){
console.log(this.name);
}
then .bind(objectWithoutMethod) will do something like :
function(){
console.log(objectWithoutMethod.name);
}
and then assign this function reference to var functionWithObjectBound
so when you run the functionWithObjectBound in global context the this already had explicitely bound to
objectWithoutMethod, so the function will print "Object WithOut Method".
*/
/*one can also directly call the above line like : */
objectWithMethod.objMethod.bind(objectWithoutMethod)();
/************Apply and Call*****************
The Apply and Call methods are two of the most often used Function methods in JavaScript, and for good reason: they allow us to borrow functions and set the this value in function invocation. In addition, the apply function in particular allows us to execute a function with an array of parameters, such that each parameter is passed to the function individually when the function executes—great for variadic functions; a variadic function takes varying number of arguments, not a set number of arguments as most functions do.
*/
/******** Apply ****************/
var ordnryObj = {
/* this object dont have any mehthod define which can set its fullName to a definite value */
fullName: null
};
var objWithFullNameMethod = {
/* this object have a method which can set its fullName to a proper value */
fullName: null ,
fullNameMethod: function (frstNam, lstNam) {
this.fullName = frstNam + " " + lstNam;
}
};
/* if we want "ordnryObj" to set its "fullName" property by a method which it dont have, so the option
is to borrow a method from an object which has the same property name "fullName" so that we can dyanmically call
that object method and set the context object to "ordnryObj" */
objWithFullNameMethod.fullNameMethod.apply(ordnryObj, ["Rishank", "Gupta"]);
/*in above call we have borrowed the "fullNameMethod" of "objWithFullNameMethod" and setting its
this object to the "ordnryObj" (first parameter of apply function is always an object) and since the
"fullNameMethod" requires two input parameter , we are passing the parameter value to an array ,becuase
apply expects its second argument an array of parameter values which the called method expects,
internally system will map the ["Rishank" to frstNam and "Gupta" lstNam], so this call will
call the method in context of "ordnryObj" and will set the this.fullName of "ordnryObj" to "Rishank Gupta"
*/
console.log(ordnryObj.fullName);/* "Rishank Gupta" */
/*********** Call ******************/
/* In "Call" only one difference is there that it requires the argument required by the borrowed
function to be passed as comma sepearted values that we usually passed to a normal function with parameters */
objWithFullNameMethod.fullNameMethod.call(ordnryObj, "Oracle", "Financial Services Software");
console.log(ordnryObj.fullName);/* "Oracle Financial Services Software" */
Comments
Post a Comment