this is a JavaScript keyword, not a variable. Unlike variables [variables declared within a function are visible throughout the function (including within nested functions) but do not exist outside of the function.] , the this keyword does not have a scope, and nested functions do not inherit the this value of their caller. If a nested function is invoked as a method, its this value is the object it was invoked on. If a nested function is invoked as a function then its this value will be either the global object (non-strict mode) or undefined (strict mode). It is a common mistake to assume that a nested function invoked as a function can use this to obtain the invocation context of the outer function. If you want to access the this value of the outer function, you need to store that value(this) into a variable that is in scope for the inner function. It is common to use the variable self for this purpose.
For example:
var o = { // An object o.
m: function() { // Method m of the object.
var self = this; // Save the this value in a variable.
console.log(this === o); // Prints "true": this is the object o.
f(); // Now call the helper function f().
function f() { // A nested function f
console.log(this === o); // "false": this is global or undefined
console.log(self === o); // "true": self is the outer this value.
}
}
};
o.m(); // Invoke the method m on the object o.
Console:
true
false
true
// A step further
var o = { // An object o.
m: function() { // Method m of the object.
//every function invocation has a this value, and a
//closure cannot access the this value of its outer function
//unless the outer function has saved that value into a variable
var self = this; // Save the this value in a variable.
console.log(this === o); // Prints "true": this is the object o.
f.bind(this)(); // Bind f to o using 'this' then call f().
function f() { // A nested function f
console.log(this === o); // "true": this is now bound to o
console.log(self === o); // "true": self is the outer this value.
}
}
};
o.m(); // Invoke the method m on the object o
Console:
true
true
true
// Credit to Richard Of Stanley
// This data variable is a global variable
var data = [
{member:"R. Nadal", age:28},
{member:"R. Federer", age:33}
]
var user = {
// local data variable
data :[
{member:"L. James", age:28},
{member:"M. Jordan", age:53}
],
viewData:function (event) {
var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1
console.log (this.data[randomNum].member + " " + this.data[randomNum].age);
}
}
// Assign the viewData method of the user object to a variable
var viewDataVar = user.viewData;
viewDataDataVar(); // R. Nadal 28 (from the global data array, not from the local data array)
Console:
R. Nadal 28
When we execute the viewDataVar () function, the values printed to the console are from the global data array, not the data array in the user object. This happens because viewDataVar () is executed as a global function and use of this inside viewDataVar () is bound to the global scope, which is the window object in browsers.
// A step further
// This data variable is a global variable
var data = [
{member:"R. Nadal", age:28},
{member:"R. Federer", age:33}
]
var user = {
// local data variable
data :[
{member:"L. James", age:28},
{member:"M. Jordan", age:53}
],
viewData:function (event) {
var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1
console.log (this.data[randomNum].member + " " + this.data[randomNum].age);
}
}
//Invoke the method viewData on the object user
user.viewData(); //from the local data array
var viewDataDataVar = user.viewData;
viewDataDataVar();//from the global data array
Console:
L. James 28
R. Nadal 28
When we execute the user.viewData() , the values printed to the console are from the data array in the user object. This happens because user.viewData() is executed as a method of user(Yes, a method of user object, I am right about this) and use of this inside user.viewData() is bound to the user object. // This data variable is a global variable
var data = [
{member:"R. Nadal", age:28},
{member:"R. Federer", age:33}
]
var user = {
// local data variable
data :[
{member:"L. James", age:28},
{member:"M. Jordan", age:53}
],
viewData:function (event) {
var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1
console.log (this.data[randomNum].member + " " + this.data[randomNum].age);
}
}
// Bind the viewData method to the user object
var viewDataDataVar = user.viewData.bind(user);
//Now the we get the value from the user object because the this keyword is bound to the user object
viewDataDataVar();
Console:
L. James 28
var myObj = {
_Function: function () {},
__Function: function () {},
getAsyncData: function (cb) {
cb();
},
render: function () {
var self = this;
this.getAsyncData(function () {
this._Function();//ERROR
self.__Function();//OK
});
}
};
myObj.render();
Console:
Uncaught TypeError: Object [object global] has no method '_Function'
We need to keep the context of the myObj object referenced for when the callback function is called. Calling self._Function() enables us to maintain that context and correctly execute our function.
var myObj = {
_Function: function () {
console.log('_Function');
},
__Function: function () {
console.log('__Function');
},
getAsyncData: function (cb) {
cb();
},
render: function () {
var self = this;
this.getAsyncData(function () {
self._Function();//No more Error
self.__Function();
});
}
};
myObj.render();
However, this could be neatened somewhat by using Function.prototype.bind().
Let’s rewrite our example:
var myObj = {
_Function: function () {
console.log('_Function');
},
__Function: function () {
console.log('__Function');
},
getAsyncData: function (cb) {
cb();
},
render: function () {
this.getAsyncData(function () {
this._Function();
this.__Function();
}.bind(this));
}
};
myObj.render();
Console:
_Function
__Function
No comments:
Post a Comment