Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Javascript scope with "var that = this" [duplicate]

Tags:

javascript

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'?

like image 955
Scott Avatar asked Sep 11 '12 13:09

Scott


2 Answers

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.

like image 147
apsillers Avatar answered Nov 16 '22 02:11

apsillers


Because this changes its value based on the context it's run in.

Inside your selectButtonClick function the this will refer to that function's context, not the outer context. So you need to give this a different name in the outer context which it can be referred to by inside the selectButtonClick function.

like image 31
Gareth Avatar answered Nov 16 '22 03:11

Gareth