使用回调和闭包时,在Javascript中维护对"this"的引用

and*_*yuk 40 javascript node.js

我发现自己将"this"分配给变量,因此我可以在回调和闭包中轻松使用它.

这是不好的做法吗?有没有更好的方式回顾原始功能?

这是一个典型的例子.

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) {

};
Run Code Online (Sandbox Code Playgroud)

您通常使用这种方法还是找到了更清洁的解决方案?

hug*_*omg 85

this回调有三种主要处理方式:

1.创建一个词法范围的变量,就像您目前正在做的那样

这个新变量的两个最常见的名称是thatself.我个人更喜欢使用,that因为浏览器有一个名为self的全局窗口属性,如果我影响它,我的linter会抱怨.

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

这种方法的一个优点是,一旦代码转换为使用,that您可以根据需要添加尽可能多的内部回调,并且由于词法范围,它们都将无缝地工作.另一个优点是它非常简单,即使在古老的浏览器上也能工作.

2.使用.bind()方法.

Javascript函数有一个.bind()方法,可以让您创建具有固定版本的版本this.

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

当涉及到处理时this,bind方法对于一个回调特别有用,其中必须添加包装函数会更详细:

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

var that = this;
setTimeout(function(){ that.doSomething() }, 500);
Run Code Online (Sandbox Code Playgroud)

主要的缺点bind是,如果你有嵌套的回调,那么你还需要调用bind它们.此外,IE <= 8和其他一些旧浏览器,本身并不实现该bind方法,因此如果您仍需要支持它们,则可能需要使用某种填充库.

3.如果需要对函数作用域或参数进行更细粒度的控制,请回退到.call()和.apply()

控制在JavaScript函数的参数,包括更原始的方式this,是.call().apply()方法.它们允许您使用任何对象调用函数this作为其参数和任何值作为参数.apply对于实现可变参数函数特别有用,因为它接收参数列表作为数组.

例如,这是一个bind版本,它接收绑定为字符串的方法.这让我们this只记下一次而不是两次.

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

setTimeout(myBind(this, 'someMethod'), 500);
Run Code Online (Sandbox Code Playgroud)

  • 有趣的是,我只是在nodejs中运行了一个(非常简单的)基准测试,方法1比方法2快了100倍. (4认同)
  • 跑了类似的基准.我没有快100倍,但使用闭包方法仍然明显更快. (3认同)