使用回调和闭包时在 Javascript 中维护对“this”的引用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7874723/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Maintaining the reference to "this" in Javascript when using callbacks and closures
提问by andyuk
I find myself assigning "this" to a variable so I can easily use it in callbacks and closures.
我发现自己将“this”分配给了一个变量,这样我就可以轻松地在回调和闭包中使用它。
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?
您通常使用这种方法还是找到更清洁的解决方案?
回答by hugomg
There are three main ways to deal with this
in callbacks:
this
在回调中主要有三种处理方式:
1. Create a lexically-scoped variable, as you are currently doing
1. 创建一个词法范围的变量,就像你目前所做的那样
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.
这个新变量的两个最常见的名称是that
和self
。我个人更喜欢使用,that
因为浏览器有一个名为 self 的全局窗口属性,如果我隐藏它,我的 linter 会抱怨。
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.
这种方法的一个优点是,一旦将代码转换为 using,that
您就可以根据需要添加任意数量的内部回调,并且由于词法范围,它们都将无缝地工作。另一个优点是它非常简单,甚至可以在古老的浏览器上运行。
2. Use the .bind() method.
2. 使用 .bind() 方法。
Javascript functions have a .bind()
method that lets you create a version of them that has a fixed this
.
Javascript 函数有一种.bind()
方法,可以让您创建它们的版本,该版本具有固定的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:
在处理 时this
,bind 方法对于必须添加包装函数会更加冗长的回调之一特别有用:
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 libraryif you still have to support them.
的主要缺点bind
是,如果您有嵌套的回调,那么您还需要调用bind
它们。此外,IE <= 8 和其他一些旧浏览器,不会在本地实现该bind
方法,因此如果您仍然需要支持它们,您可能需要使用某种填充库。
3. If you need more fine-grained control of function scope or arguments, fall back to .call() and .apply()
3. 如果您需要对函数作用域或参数进行更细粒度的控制,请回退到 .call() 和 .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.
在 Javascript 中控制函数参数的更原始的方法,包括this
、.call()
和.apply()
方法。它们让您可以使用任何对象this
作为其参数和任何值来调用函数。apply
对实现可变参数函数特别有用,因为它以数组的形式接收参数列表。
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.
例如,这里有一个 bind 版本,它接收绑定为字符串的方法。这让我们this
只写一次而不是两次。
function myBind(obj, funcname){
return function(/**/){
return obj[funcname].apply(obj, arguments);
};
}
setTimeout(myBind(this, 'someMethod'), 500);
回答by Tomasz Nurkiewicz
Unfortunately this is the well-established way to do this, although that
is a widespread naming convention for this
"copy".
不幸的是,这是一种行之有效的方法,尽管这that
是this
“复制”的广泛命名约定。
You can also try:
你也可以试试:
db.User.findById('ABCD', this.foo.bind(this));
But this approach requires foo()
to have exactly the same signature as the one expected by findById()
(in your example you are skipping err
).
但是这种方法需要foo()
具有与预期完全相同的签名findById()
(在您的示例中您正在跳过err
)。
回答by Yoshi
You could create a proxy for the callback with:
您可以使用以下方法为回调创建代理:
var createProxy = function(fn, scope) {
return function () {
return fn.apply(scope, arguments);
};
};
Using this, you could do the following:
使用它,您可以执行以下操作:
db.User.findById('ABCD', createProxy(function(err, user)) {
this.foo(user);
}, this));
jQuery does something similar with: $.proxy
jQuery 做了类似的事情:$.proxy
And, as others have noted using bind
, have a look here if compatibility is an issue:
而且,正如其他人所指出的bind
,如果兼容性有问题,请查看此处:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind#Compatibility
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind#Compatibility