Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
288 views
in Technique[技术] by (71.8m points)

node.js - Maintaining the reference to "this" in Javascript when using callbacks and closures

I find myself assigning "this" to a variable so I can easily use it in callbacks and closures.

Is this bad practice? Is there a better way of referring back to the original function?

Here is a typical example.

User.prototype.edit = function(req, res) {

  var self = this,
      db = this.app.db;

  db.User.findById('ABCD', function(err, user)) {

    // I cannot use this.foo(user)
    self.foo(user);
  });
};

User.prototype.foo = function(user) {

};

Do you normally use this approach or have you found a cleaner solution?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are three main ways to deal with this in callbacks:

1. Create a lexically-scoped variable, as you are currently doing

The two most common names for this new variable are that and self. I personally prefer using that because browsers have a global window property called self and my linter complains if I shadow it.

function edit(req, res) {
    var that = this,
    db.User.findById('ABCD', function(err, user){
        that.foo(user);
    });
};

One advantage of this approach is that once the code is converted to using that you can add as many inner callbacks as you want and they will all seamlessly work due to lexical scoping. Another advantage is that its very simple and will work even on ancient browsers.

2. Use the .bind() method.

Javascript functions have a .bind() method that lets you create a version of them that has a fixed this.

function edit(req, res) {
    db.User.findById('ABCD', (function(err, user){
        this.foo(user);
    }).bind(this));
};

When it comes to handling this, the bind method is specially useful for one-of callbacks where having to add a wrapper function would be more verbose:

setTimeout(this.someMethod.bind(this), 500);

var that = this;
setTimeout(function(){ that.doSomething() }, 500);

The main disadvantage of bind is that if you have nested callbacks then you also need to call bind on them. Additionally, IE <= 8 and some other old browsers, don't natively implement the bind method so you might need to use some sort of shimming library if you still have to support them.

3. If you need more fine-grained control of function scope or arguments, fall back to .call() and .apply()

The more primitive ways to control function parameters in Javascript, including the this, are the .call() and .apply() methods. They let you call a function with whatever object as their this and whatever values as its parameters. apply is specially useful for implementing variadic functions, since it receives the argument list as an array.

For example, here is a version of bind that receives the method to bind as a string. This lets us write down the this only once instead of twice.

function myBind(obj, funcname){
     return function(/**/){
         return obj[funcname].apply(obj, arguments);
     };
}

setTimeout(myBind(this, 'someMethod'), 500);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...