6

Possible Duplicate:
JS: var self = this?

When looking at arbitrary code written in JavaScript (e.g. on GitHub), many developers use var self = this and then use self instead of this to reference the current object.

What is the rationale behind this approach?

Community
  • 1
  • 1
Scholle
  • 1,521
  • 2
  • 23
  • 44
  • 3
    Passing a parent-scope element into a child scope when it is called/accessed "out of scope" to the parent. It has to do with closures and maintaining context. – Jared Farrish Aug 11 '12 at 22:22

4 Answers4

9

The value of this is contextual. Writing var self = this is a way to save the value of this in one context so that it can be used in another.

Example:

function Test() {
    var self = this;
    console.log(this);
    setTimeout(function() {
        console.log(this);
        console.log(self);
    }, 1000);
}

Prints:

Test {}
Window 11918143#comment15869603_11918143
Test {}

Notice that the value of this has changed, but we can still refer to the original value using self.

This works because functions in JavaScript "close over" the variables in their lexical scope (which is just a more technical way of saying that the inner function can see variables declared in the outer function). This is why we write var self = this; the variable self is available to all inner functions, even if those functions don't execute until long after the outer function has returned.

Wayne
  • 59,728
  • 15
  • 131
  • 126
  • 1
    @Blender - Which I've now ruined with an example :) – Wayne Aug 11 '12 at 22:29
  • No offense, but I don't think this really describes the underlying functionality, which is that one context is not destroyed in it's containing context with remaining references (the variables still in-scope). This is (*gasp*) simplistic. – Jared Farrish Aug 11 '12 at 22:33
  • @JaredFarrish - Fair enough. More explanation added. Definitely more detail than the accepted answer :) – Wayne Aug 11 '12 at 22:40
  • I like. `:)` Note, I did not *downvote* but I did *upvote*. – Jared Farrish Aug 11 '12 at 22:44
  • @lwburk: Your answer uses JS language concepts only, which I prefer, but your example should contain "var self = this", so that it's already clear when just looking the sample code provided. – Scholle Aug 11 '12 at 22:46
  • @Scholle - In defense of this answer (pre my bitching), lwburk was *demonstrating* why *not* using a `var = whatever` is problematic. If you don't *get* this, you may not actually understand the underlying problem. – Jared Farrish Aug 11 '12 at 22:49
  • I actually think @Scholle's point is fair. It's possible to demonstrate both things at once, which my last update does, I think. Thanks to you both for good feedback. – Wayne Aug 11 '12 at 22:51
  • I guess I get to pimp my jsFiddle again: http://jsfiddle.net/hTdEC/1/ Which more or less demonstrates both... LOL – Jared Farrish Aug 11 '12 at 22:53
  • All of this back-and-forth is going to seem really silly when this gets closed as a dup :) – Wayne Aug 11 '12 at 22:55
  • Nah. I was bored anyhow; only so many Knockout.js tutorial videos a man can watch when the Olympics isn't on. – Jared Farrish Aug 11 '12 at 22:56
  • Jeff and Joel are right. This kind of discussion is useless and should be deleted from the internet because WE ARE TOTALLY RUNNING OUT OF BITS AND THERE IS NO ROOM LEFT FOR THIS AND THE DUP! – Wayne Aug 11 '12 at 22:59
5

When you are using a callback in jQuery, for example, you may want to reference the parent function's this variable, which takes a different value once you are in another function:

$('#foo').click(function() {
  var self = this;

  $.get('foo.php', function(data) {
    // In here, self != this

    $(self).text(data);
  });
});

In this case, replacing $(self) with $(this) would not work. Basically, you're storing this in a variable for later use.

Blender
  • 289,723
  • 53
  • 439
  • 496
2

Usually when you have a nested function declaration inside some code but you want to refer to the "parent" function from inside the "child" function.

Ext.define('MyPanel', {
    extend: 'Ext.panel.Panel',

    title: 'My Panel',

    initComponent: function() {

        var self = this;

        Ext.applyIf(self, {
            items: [
                {
                xtype: 'button',
                text: 'MyButton',
                handler: function() {
                    console.log(this); //the button
                    console.log(self); //the panel
                }}
            ]
        });

        self.callParent(arguments);
    }
});

Ext.onReady(function() {

    var p = new MyPanel({
        renderTo: Ext.getBody()
    });


});​

Example:

http://jsfiddle.net/8F4UN/

Neil McGuigan
  • 46,580
  • 12
  • 123
  • 152
2

Let me give a somewhat more technical explanation. When you access a variable in Javascript, the interpreter looks for the value of the variable in what's known as the scope stack. You can think of it as a stack of Objects. The interpreter will look first at the top of the stack. If the variable isn't defined in that scope object, it will look at the object beneath it. If it's not there, the interpreter looks another level down until it hits the bottom of the stack.

Initially, the only scope object in the stack is the global object. A variable is either there or not. When you call a function, the interpreter pushes a new object onto the scope stack--to be used for storing local variables. When you access var1, the interpreter will first look in the local scope object. If it's there, then it'll use the value stored there. If it's not, it moves on to the scope object further down the stack--which happens to be the global scope.

When you create a function within a function, something interesting happens. The interpreter will create what's known as an "activation object". It's basically a snapshot of the local scope object of the outer function. This activation object becomes associated with the inner function. When the inner function is called, the activation object is push onto the scope stack before the local scope (i.e. the local scope would still be at the top). Access of a variable in the inner function means the interpreter will first check the local scope object, then the activation object, then the global scope object.

By definition, the this variable always exists in the local scope of a function. It always refers to the implicit first argument. When you call a plain-o function, the compiler passes null as this. The variable exists, but points to null. A search for this would never look beyond the local scope object.

The purpose of the assignment to self is basically to fool the interpreter, so that it would look beyond the local scope of the inner function. When you access self in the inner function, the interpreter wouldn't find it in the local scope. So it checks the activation object. Provided that the self = this statement occurs before the creation of the inner function, self would exist in the activation scope object, pointing to the this object seen by the outer function.

cleong
  • 7,242
  • 4
  • 31
  • 40