简体   繁体   中英

JavaScript: creating a reference to 'this' (e.g. 'var _this = this') vs. bind/call/apply

Relying on this in the wrong context is a common pitfall. A contrived example:

function SomeClass() {
    this.prop = 42;
    document.body.addEventListener('click', function() {
        alert(this.prop); // will be undefined
    });
}
new SomeClass();

One way around this is using bind (or call or apply ), for example:

function SomeClass() {
    this.prop = 42;
    document.body.addEventListener('click', (function() {
        alert(this.prop); // works
    }).bind(this));
}
new SomeClass();

Another option is to make a reference to this available via closure, usually _this or self :

function SomeClass() {
    var _this = this;
    this.prop = 42;
    document.body.addEventListener('click', function() {
        alert(_this.prop); // works
    });
}
new SomeClass();

I prefer the latter method, because I can declare it once rather than wrapping loads of functions with bind() , and nested callbacks (which I know are not ideal, but are seen in the wild) become simpler. But I have the sneaking suspicion that either a) there are gotchas with this method, or b) the fact that I have to do this or bind in the first place means that I'm doing it wrong. Any thoughts?

Your method to address the "issue of this" is OK:


function SomeClass() {
    this.prop = 42;
    document.body.addEventListener('click', (function() {
        alert(this.prop); // works
    }).bind(this));
}
new SomeClass();

You really are not doing anything wrong if you found you need doing this, but depending on context, if you are worried about performance maybe you don't want to create new functions (that is what .bind internally does to change this )

Instead of doing the binding, you can use an scope variable, like your second example:


function SomeClass() {
    var _this = this;
    this.prop = 42;
    document.body.addEventListener('click', function() {
        alert(_this.prop); // works
    });
}
new SomeClass();

The only remaining issue here, is about code readability, but I thing is matter of tastes, this what I would do for this particular case


function SomeClass() {
    var prop = 42;
    document.body.addEventListener('click', function() {
        alert(prop); // works
    });
}
new SomeClass();

I just improved readability and maybe a little of performance, but I am not meaning that is "the way" to do it, I am trying to say you should know how to use lexical scoping and closures and use that (or not) where/when you think you have to (all depends on context, of course)

EDIT : wait!, I assigned this.prop = 42 because I need to expose the property On that case, I think the best practice from design PoV is to expose it via a getter:


function SomeClass() {
    var prop = 42;
    document.body.addEventListener('click', function() {
        alert(prop); // works
    });
    this.getProp = function() {
      return prop;
    };

    this.setProp = function(newValue) { // prop is supposed to be modifiable ?
      prop = newValue;
    };
}
new SomeClass();

Another side note about design not related with the "this" issue, it doesn't feel right to interact with global objects from the class, I would do something like thus:


function SomeClass(receiver) {
    var prop = 42;
    receiver.addEventListener('click', function() {
        alert(prop); // works
    });
}
new SomeClass(document.body);

Are there gotchas with this method?

No, it's fine. I'd even argue that there are less gotchas than with bind (and its ES3 non-support). A pitfall that is sometimes seen is to forget var (and introducing a global variable if not in strict mode), but if you understood closures that's probably not a problem any more.

Or does the fact that I have to do this or bind in the first place mean that I'm doing it wrong.

No, that's just how calling methods that use this works in JavaScript. I'm not saying that a wrong design can't require an abnormally frequent use of self / bind , but good designs do contain this pattern as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM