2

I understand that JavaScript automatically assigns each function/method the parameter this, and that this is bound to the object which contains it.

A method is a function stored as the property of an object. So in a method, this can be used to modify or retreive values from the object that contains it. But if that method is invoked as a function, not as the property of an object, then this is bound to global, not to the object.

The workaround is to assign:

var that = this;

inside the method, so that an inner function can have access to this through the variable that.

My question is: Why is this workaround necessary? Can't you just use methods all the time? Why would you invoke a perfectly good method as an inner function, and then have to make another variable so that it has the access it would have had had it been invoked as a method instead?

I must be missing something important here, if there were a dumb-question tag, I would use it. (can someone make one?)

ridthyself
  • 779
  • 1
  • 6
  • 16
  • This answer has a lot of good info around closures: http://stackoverflow.com/a/111200/573218 – John Koerner Sep 20 '13 at 15:09
  • 1
    Note that ECMAScript introduces [arrow functions](http://robcee.net/2013/fat-arrow-functions-in-javascript) which preserve this. By using them, you could effectively get away without the horrible `_this = that = self = this` nonsense. As a side-note, I think `this` is terrible because of its ambiguous name, and using a synonym such as `that` does very little do help. Using something descriptive that actually clearly indicates the object being referred to does wonders for understanding code like this (hahaha). – Barney Sep 20 '13 at 15:37
  • @Barney nice, the => function looks promising. – ridthyself Sep 20 '13 at 18:08

4 Answers4

2

I hope that I understand your question right . because the way you put it is a bit of mind-f*** XD .

but from what i understood . im going to answer your question as in "what do we use the that trick for ? ".

So here is a perfectly healthy object .

var myobject = {
    firstMethod : function(){
        this.secoundMethod(); // calls the other method

    },
    scoundMethod : function(){
        return 'hi from method 2' ;
    }
} 

and now i want to do some jquery magic (or any other thing that has a call back function) . im going to use jQuery but feel free to do other things .

var myobject = {
    firstMethod : function(){
        var _this = this ;
        this.secoundMethod(); // calls the other method

        $('.myClass').animate({'width':300} , 300 , function(){
            // this is a call back functon which will be called as soon as the animation ends
            // the problem is that if i call @var : `this` , it wont work because im in 
            // another scope other than the firstMethod .
            // so the following will throw an error .
            this.secoundMethod(); // error

            // to solve this you need the @var : `that` , or in my case i love it to be _this
            _this.scoundMethod() // this will work .


        })

    },
    scoundMethod : function(){
        return 'hi from method 2' ;
    }
} 

So mainly _this (in my case) is used to scope things . so I can access the object scope inside other scope . to be honest i have used this trick in other places (in like 99% of cases);

even the 1% that is left is basically the same idea but with much deeper nesting or with lots of closures and stuff like that.

How dangerous can this be ?!

Well it depends on how smart you are . here is another brain example

var myobject = {
    firstMethod : function(){
        var _this = this ,
            someObject : {

                firstMethod  : function(){
                    this.scoundMethod(); // if you log this you will get 'the wrong method'.
                    _this.scoundMethod(); // in here you get 'hi from method 2'.

                },
                scoundMethod : function(){
                    return 'the wrong method';
                }
            };

    },
    scoundMethod : function(){
        return 'hi from method 2' ;
    }
} 

As you can see this is dangerous not because it doesn't work , but the fear id that it works . because if you have similarly named functions and you have a missed-up scope you end up with hours and hours of digging . While if you dont have that .. you will get just a nice error which you can fix right away

How long can this go .

will you can nest as much as you like . but there are consequences (rarely huh?!). enjoy the following and dont ever attempt that at home .

var myobject = {
    firstMethod : function(){
        var _this = this ,
            someVar = [1 , 2 , 3 ] ;

            this.scoundMethod(function(){
                var that = this;
                $.each(someVar,function(elementName){
                    var them = this;
                    $('.'+elementName).animate({} , 300 , function(){
                        console.log(them) // logs the element
                        console.log(_this.scoundMethod()) // logs 'hi from method 2'
                    })
                })
            }

    },
    scoundMethod : function(){
        return 'hi from method 2' ;
    }
} 

Other resources :

Hope I have made it simple . And that I didn't answer the wrong question .

Hussein Nazzal
  • 2,539
  • 15
  • 34
  • your second example is very illuminating. It shows that a method's `this` only binds to the same depth as the method, so to bind to a higher depth, `that` variable is needed. like rockerest posted, the alternative would be to reaccomplish the scope for each nested method. – ridthyself Sep 20 '13 at 15:46
  • yeah i have made that clear in the `How long can this go .` section . it even feels weird when i say this and that .. scope is just like inception dont go deep or you will be lost for ever , hoo (then he fades slowly ) – Hussein Nazzal Sep 20 '13 at 15:51
2

The question of this and that has been eloquently and succinctly answered elsewhere, so I'll answer your question: why invoke an inner function?

Why not?

Using the linked answer as a jumping off point:

$('#element').click(function(){
    // this is a reference to the element clicked on

    var that = this;

    $('.elements').each(function(){
        // this is a reference to the current element in the loop
        // that is still a reference to the element clicked on
    });
});

What would the benefit be of instantiating a new object, passing in all the variables you need, and manually constructing the proper environment just to loop over some elements? You have the proper environment right here, and the scope is exactly where you need it.

If you need access to the this variable within an inner scope, you'll need to re-assign it, since it's being re-purposed in the inner scope. In this case, some people use that which isn't very illuminating in my opinion, but it's just a way of passing scope to these highly useful temporary inner scopes.

And that's really the key, it's temporary scope changing. There's no reason to create an entirely new scope, symbol tables, etc, etc, when you've got it all right here.

Community
  • 1
  • 1
rockerest
  • 9,847
  • 3
  • 33
  • 67
  • So a method invoked from within a method loses scope? It's not just when you call it as a function? I thought there was a difference there... This directly answers the question: you would have to reproduce the scope for each nested method. Is that right? – ridthyself Sep 20 '13 at 15:39
  • 1
    I'm not quite sure if I understand the second part of your comment, but as to the first part - "a method invoked from within a method loses scope" - I can say: it definitely doesn't! That's one of the great things about JavaScript's function-level scope definitions instead of block-level. When you enter an inner function, it still has access to it's parent scope; @Hussein demonstrates this above. What I'm demonstrating is that when you enter the inner function, the `this` variable is usually changed by entering it's scope, so you need to provide access to the originating `this` for it. – rockerest Sep 20 '13 at 20:50
2

Execution context changes for callbacks in events and timers. So the value of this becomes window.

Assigning this to that(or self) 'that' becomes a variable that can accessed through closure. The 'that' gives 'this' to the callback.

Some stuff to google: javascript closure, execution context, javascript self, javascript timer/event context.

Quentin Engles
  • 2,352
  • 1
  • 16
  • 31
0

One of the reasons is that you may want to call or apply that method on any other object if you set as its context.

    var obj = {
        name: 'foo'
    },

    logger = function (name) {
        this.name = name;
        this.log = function () {
            console.log(this.name)
        }
    };

    var bar = new logger('bar');
    bar.log(); // -> 'bar'
    bar.log.call(obj); // -> 'foo'
tikider
  • 540
  • 3
  • 12