2

Simple question. Why do we have set that = this? If we dont, we are in the global scope...but why?

var myObj = {

    specialFunction: function () {

    },

    anotherSpecialFunction: function () {

    },

    getAsyncData: function (cb) {
        cb();
    },

    render: function () {
        var that = this;
        this.getAsyncData(function () {
            // this now refers to global scope....why?
            that.specialFunction();
            that.anotherSpecialFunction();
        });
    }
};

myObj.render();
KingKongFrog
  • 12,668
  • 17
  • 63
  • 111
  • It is in callback function. *this* will change in it. you can set breakpoint to check both *that* and *this* in callback function – MarshalSHI Jan 24 '14 at 04:22
  • not sure if i follow what u said, but i think if you used 'this' inside the block this.getAsyncData, you will be referring to the sub object (this.getAsyncData), but what you want is to access the parent object myObj which is refereed as 'this' in the first level. – Mohammed Joraid Jan 24 '14 at 04:22
  • also related: [How to access the correct `this` / context inside a callback?](http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback). – Felix Kling Jan 24 '14 at 04:48

3 Answers3

2

Writing that = this doesn't change the scope. The way the anonymous function is called will always end up with this being global object,* because that's exactly what the spec says should happen. Using that = this is just a workaround.

You could make this always point to myObj by using Function.call:

var myObj = {

    specialFunction: function () {

    },

    getAsyncData: function (cb) {
        cb.apply(this);
    },

    render: function () {
        this.getAsyncData(function () {
            this.specialFunction();
        });
    }
};

and/or using Function.bind:

var myObj = {

    specialFunction: function () {

    },

    getAsyncData: function (cb) {
        cb();
    },

    render: function () {
        function callback() {
            this.specialFunction();
        }

        this.getAsyncData(callback.bind(this));
    }
};

* Unless you're in strict mode, in which case this is undefined.

Matt Ball
  • 332,322
  • 92
  • 617
  • 683
  • 2
    Oh I know that = this is a workaround. My question is simply why are we in the global scope within that function. Is it simply because it is an anonymous function? – KingKongFrog Jan 24 '14 at 04:25
  • 1
    _"Is it simply because it is an anonymous function?"_ No. It's because of how the function is **called.** In JS, a function's `this` is determined by the caller (unless `Function.bind` was used). – Matt Ball Jan 24 '14 at 04:27
  • @MattBall not clear..how are you asserting that callee is window object? – Deepak Ingole Jan 24 '14 at 04:29
  • @Pilot read the spec I linked. [10.4.3, #2.](http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.3) – Matt Ball Jan 24 '14 at 04:30
  • @MattBall thumbs up Sir..thanks.. – Deepak Ingole Jan 24 '14 at 04:32
  • 1
    @KingKongFrog—"*why are we in the global scope*"—you aren't. The value of *this* has nothing to do with scope, you're in function scope. But since *this* wasn't set in the call, it defaults to the global object (or remains undefined in strict mode). – RobG Jan 24 '14 at 06:49
0

EDIT: in JavaScript the "this" context depends on how your function is called, example:

 function helloWorld()
 {
    console.log(this);
 }

And here two ways to call this function:

new helloWorld(); note that if you call your function in this way, the context of this will be the context of the function + prototype, so your console will show this: helloWorld {}

helloWorld(); if you call your function without of the "new", the context of "this" will be global(Window), so your console will show this: Window about:home

Ok, with this little explanation i will try to explain now why you have sometimes to use self/that...

Imagine that you want to use this.name inside this.hello function. Like I said before, the context of "this" depends on how your function is called, so if you want to ensure that this.name inside of this.hello function refer to this.name outside is recommended that you use self/that to avoid what happens bellow

function helloWorld(){
             var self = this;//or that = this
             this.name = "YourName" 
             this.hello = function(){
                 console.log(this); //the context of "this" here will be: "hello {}" 
                 return this.name; //undefined, because you don't have name attribute inside hello function
             }
             new this.hello(); //note how hello is called here... 

}

var test = new helloWorld(); 

And here a good explanation about context x scope: http://ryanmorr.com/understanding-scope-and-context-in-javascript/

Rodrigo Fonseca
  • 864
  • 7
  • 21
  • 1
    Do you make it purposely difficult to read your explanation? And FWIW, how `this` works doesn't really have anything to do with scope. – Felix Kling Jan 24 '14 at 04:45
  • No, obviously not. "how this works doesn't really have anything to do with scope", ok if you are saying who i'm to contest? – Rodrigo Fonseca Jan 24 '14 at 04:57
  • *"No, obviously not."* Then you shouldn't write such awful long comment where we have to scroll horizontally. Just put the description out side of the code. – Felix Kling Jan 24 '14 at 05:01
  • ok, I've fixed it, how about being a little less rude now? – Rodrigo Fonseca Jan 24 '14 at 05:04
  • Sorry if you felt like I'm being rude, that was not my intention. – Felix Kling Jan 24 '14 at 05:05
  • *this* has nothing to do with scope, it's value is set by how a function is called. That's why the answer is seen as confusing. – RobG Jan 24 '14 at 06:52
  • ok, i agree with you guys, and here a good explanation about "context x scope": http://ryanmorr.com/understanding-scope-and-context-in-javascript/. I really thought that "this" had something to do about scope, but doesn't. – Rodrigo Fonseca Jan 24 '14 at 17:37
0

take a look at the this keyword in JavaScript and how it works. I’m sure we’ve all come across this issue:

 $("myLink").on("click", function() {
    console.log(this); //points to myLink (as expected)
    $.ajax({
        //ajax set up
        success: function() {
            console.log(this); //points to the global object. Huh?
        }
    });
});

this is a variable that is automatically set for you when a function is invoked. The value it’s given depends on how a function is invoked. In JavaScript we have a few main ways of invoking functions. I wont talk about them all today, but just the three ways most people use them; either when a function is called as a method, or on it’s own, or as an event handler. Depending on how a function is invoked, this is set differently:

function foo() {
    console.log(this); //global object
};

myapp = {};
myapp.foo = function() {
    console.log(this); //points to myapp object
}

var link = document.getElementById("myId");
link.addEventListener("click", function() {
    console.log(this); //points to link
}, false);

Doing $("myLink").on("click", function() {}) means that when the element is clicked, the function is fired. But this function is bound as an event handler, so this is set to the reference to the DOM element myLink. The success method you define within the Ajax request is just a regular function, and as such when it’s invoked, this is set to the global object, as it is when any function that’s not an event handler or an object method is.

$("myLink").on("click", function() {
    console.log(this); //points to myLink (as expected)
    var _this = this;  //store reference
    $.ajax({
        //ajax set up
        success: function() {
            console.log(this); //points to the global object. Huh?
            console.log(_this); //better!
        }
    });
});

Source: http://tinyurl.com/melbl92

  • *"points to the global object. Huh?"* Actually no, according to the documentation, `this` refers to the options passed to `$.ajax`. – Felix Kling Jan 24 '14 at 04:47
  • https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener?redirectlocale=en-US&redirectslug=DOM%2FEventTarget.addEventListener this might be helpful as a reference link to understand. i will try to see if there any good example to clarify things easily. btw, look for "The value of this within the handler" this header in the provided link – Md. Tazbir Ur Rahman Bhuiyan Jan 24 '14 at 04:52
  • I know how `this` works. I'm just telling you that inside the `success` callback, `this` refers to the options passed to `$.ajax`, and not to `window` like you claimed. So the example you choose is not the best one. – Felix Kling Jan 24 '14 at 05:02
  • thanks kling. i will try to provide good example. :) – Md. Tazbir Ur Rahman Bhuiyan Jan 24 '14 at 05:08