Wednesday, 9 August 2017

Understanding Javascript scope with "var that = this"




Say I have the following property method in an object:



  onReady: function FlashUpload_onReady()
{

Alfresco.util.Ajax.jsonGet({
url: Alfresco.constants.PROXY_URI + "org/app/classification",
successCallback: {
fn: function (o) {
var classButtonMenu = [],
menuLabel, that = this;

var selectButtonClick = function (p_sType, p_aArgs, p_oItem) {
var sText = p_oItem.cfg.getProperty("text");
that.classificationSelectButton.set("label", sText);

};

for (var i in o.json.items) {
classButtonMenu.push({
text: o.json.items[i].classification,
value: o.json.items[i].filename,
onClick: {fn: selectButtonClick}
});
}


this.classificationSelectButton = new YAHOO.widget.Button({
id: this.id + "-appClassification",
type: "menu",
label: classButtonMenu[0].text,
name: "appClassification",
menu: classButtonMenu,
container: this.id + "-appClassificationSection-div"
});
},
scope: this

},
failureMessage: "Failed to retrieve classifications!"
});


It took me some guess work to figure out that in the selectButtonClick function that I needed to reference that instead of this in order to gain access to this.classificationSelectButton (otherwise it comes up undefined), but I'm uncertain as to why I can't use this. My best guess is that any properties in the overall object that gets referenced within new YAHOO.widget.Button somehow looses scope once the constructor function is called.



Could someone please explain why it is that I have to reference classificationSelectButton with var that = this instead of just calling `this.classificationSelectButton'?


Answer



The most important thing to understand is that a function object does not have a fixed this value -- the value of this changes depending on how the function is called. We say that a function is invoked with some a particular this value -- the this value is determined at invocation time, not definition time.





  • If the function is called as a "raw" function (e.g., just do someFunc()), this will be the global object (window in a browser) (or undefined if the function runs in strict mode).

  • If it is called as a method on an object, this will be the calling object.

  • If you call a function with call or apply, this is specified as the first argument to call or apply.

  • If it is called as an event listener (as it is here), this will be the element that is the target of the event.

  • If it is called as a constructor with new, this will be a newly-created object whose prototype is set to the prototype property of the constructor function.

  • If the function is the result of a bind operation, the function will always and forever have this set to the first argument of the bind call that produced it. (This is the single exception to the "functions don't have a fixed this" rule -- functions produced by bind actually do have an immutable this.)




Using var that = this; is a way to store the this value at function definition time (rather than function execution time, when this could be anything, depending on how the function was invoked). The solution here is to store the outer value of this in a variable (traditionally called that or self) which is included in the scope of the newly-defined function, because newly-defined functions have access to variables defined in their outer scope.


No comments:

Post a Comment

casting - Why wasn't Tobey Maguire in The Amazing Spider-Man? - Movies & TV

In the Spider-Man franchise, Tobey Maguire is an outstanding performer as a Spider-Man and also reprised his role in the sequels Spider-Man...