What underlies this JavaScript idiom: var self = this?

164,822

Solution 1

See this article on alistapart.com. (Ed: The article has been updated since originally linked)

self is being used to maintain a reference to the original this even as the context is changing. It's a technique often used in event handlers (especially in closures).

Edit: Note that using self is now discouraged as window.self exists and has the potential to cause errors if you are not careful.

What you call the variable doesn't particularly matter. var that = this; is fine, but there's nothing magic about the name.

Functions declared inside a context (e.g. callbacks, closures) will have access to the variables/function declared in the same scope or above.

For example, a simple event callback:

function MyConstructor(options) {
  let that = this;

  this.someprop = options.someprop || 'defaultprop';

  document.addEventListener('click', (event) => {
    alert(that.someprop);
  });
}

new MyConstructor({
  someprop: "Hello World"
});

Solution 2

I think the variable name 'self' should not be used this way anymore, since modern browsers provide a global variable self pointing to the global object of either a normal window or a WebWorker.

To avoid confusion and potential conflicts, you can write var thiz = this or var that = this instead.

Solution 3

Yes, you'll see it everywhere. It's often that = this;.

See how self is used inside functions called by events? Those would have their own context, so self is used to hold the this that came into Note().

The reason self is still available to the functions, even though they can only execute after the Note() function has finished executing, is that inner functions get the context of the outer function due to closure.

Solution 4

It should also be noted there is an alternative Proxy pattern for maintaining a reference to the original this in a callback if you dislike the var self = this idiom.

As a function can be called with a given context by using function.apply or function.call, you can write a wrapper that returns a function that calls your function with apply or call using the given context. See jQuery's proxy function for an implementation of this pattern. Here is an example of using it:

var wrappedFunc = $.proxy(this.myFunc, this);

wrappedFunc can then be called and will have your version of this as the context.

Solution 5

As others have explained, var self = this; allows code in a closure to refer back to the parent scope.

However, it's now 2018 and ES6 is widely supported by all major web browsers. The var self = this; idiom isn't quite as essential as it once was.

It's now possible to avoid var self = this; through the use of arrow functions.

In instances where we would have used var self = this:

function test() {
    var self = this;
    this.hello = "world";
    document.getElementById("test_btn").addEventListener("click", function() {
        console.log(self.hello); // logs "world"
    });
};

We can now use an arrow function without var self = this:

function test() {
    this.hello = "world";
    document.getElementById("test_btn").addEventListener("click", () => {
        console.log(this.hello); // logs "world"
    });
};

Arrow functions do not have their own this and simply assume the enclosing scope.

Share:
164,822
Thomas L Holaday
Author by

Thomas L Holaday

Updated on August 01, 2022

Comments

  • Thomas L Holaday
    Thomas L Holaday almost 2 years

    I saw the following in the source for WebKit HTML 5 SQL Storage Notes Demo:

    function Note() {
      var self = this;
    
      var note = document.createElement('div');
      note.className = 'note';
      note.addEventListener('mousedown', function(e) { return self.onMouseDown(e) }, false);
      note.addEventListener('click', function() { return self.onNoteClick() }, false);
      this.note = note;
      // ...
    }
    

    The author uses self in some places (the function body) and this in other places (the bodies of functions defined in the argument list of methods). What's going on? Now that I've noticed it once, will I start seeing it everywhere?

  • steve
    steve over 10 years
    For me the cogent point is that self has no special meaning. I personally prefer using a var named something other than self since it frequently confuses me, as I expect 'self' to be a reserved word. So I like your answer. And in the example of the OP, I'd prefer var thisNote = this or similar.
  • djheru
    djheru about 10 years
    I usually use _this
  • o_o_o--
    o_o_o-- almost 10 years
    @djheru +1. so much nicer than "that" (which my brain will never get used to).
  • miphe
    miphe over 9 years
    @prior I think it makes sense up until the last paragraph.
  • GreenAsJade
    GreenAsJade over 9 years
    @JohnPaul ... this does provide an answer. It might not be the right answer, but how can you say that "it is being used to ... " is not an answer to "why did he do this"?
  • mattLummus
    mattLummus about 9 years
    @steve agreed, although I try to avoid using this/self references in general as they are very brittle in terms of maintainability.
  • Mopparthy Ravindranath
    Mopparthy Ravindranath almost 9 years
    I started using "me" :)
  • Beejor
    Beejor almost 9 years
    Until modern browsers start providing a global variable _this, that, or me.
  • Bergi
    Bergi over 8 years
    There's absolutely no problem with using the name self as long as you declare it as a variable, it'll shadow the global. Of course if you forgot the var then it wouldn't work with any other name either.
  • aaaaaa
    aaaaaa about 8 years
    @Bergi - One problem is that eslint won't catch it as an error if you forget to declare 'var self = this'.
  • Bergi
    Bergi about 8 years
    @aaaaaa It does not? Have you declared self as an implicit global to eslint somewhere?
  • aaaaaa
    aaaaaa about 8 years
    @Bergi Nope - it's implied via the browser environment: "env": { "browser": true }
  • Duan Yao
    Duan Yao almost 8 years
    @Matian2040 Existing codes which use var self = this continue to work, because the global self is shadowed, as @Bergi said. However If someone tries to modify existing code without carefully check existing uses of self in the same scope, he/she may unintentionally shadow the global self and breaks the code. That's why var self = this should be avoided.
  • jatazoulja
    jatazoulja over 7 years
    @djheru I agree with the concept of this to annotate top level this, and for me if the scope gets even deeper prepending additional "" would work for me. __this = this; or it can be any prefix (except for $) :D
  • Farhana Naaz Ansari
    Farhana Naaz Ansari almost 6 years
    You should add some explanation with code that what you did special.
  • Benjamin R
    Benjamin R over 5 years
    Or – shock, horror! – why not pass the actual relevant thing as an argument to your function (closure)? Why the hell are you referencing out of scope state, why the hell is anyone programming like this? There is never any real reason to do this. Instead .addEventListender("click", (x) => { console.log(x); }); You've explained the how and why very clearly, and I agree using arrow functions makes more sense, but still... this is just terrible, lazy, messy, programming.
  • Elliot B.
    Elliot B. over 5 years
    In JavaScript, referring back to the parent scope is extremely common and necessary. It's a fundamental part of the language. Your suggestion to pass in the parent scope as an argument on the event handler isn't actually possible. Also, in ES6, arrow functions use lexical scoping — 'this' refers to it's current surrounding scope and no further -- it's not "referencing out of scope state" or anything like that.
  • Bob Stein
    Bob Stein over 4 years
    Appears that article morphed into using var that = this;
  • Bob Stein
    Bob Stein over 4 years
    they is fashionably singular. The animate variant of this.
  • Pradeep Kumar
    Pradeep Kumar over 4 years
    @BobStein Thanks. I'll update the answer accordingly.
  • Nithin B
    Nithin B about 2 years
    Some explanation would be helpful here. You can see difference if you do var temp = thisss.sayHi and then call temp(). Now this.firstname will give undefined and that.firstname will give value because of closure created because of that variable.