我在几乎所有的knockout.js视图模型中看到了行var self = this
,然后所有局部变量都被引用为self.variableName
。与使用this.variableName
相比,这有什么好处?
答案 0 :(得分:39)
通常,使用此方法的主要原因是使当前this
可用于子功能或闭包。例如:
var myObject = {
param: 123,
method: function(){
alert( this.param );
},
method2: function(){
setTimeout(function(){
alert( this.param );
},100);
}
}
在上面的调用中myObject.method
会为您提供123
的正确提示。但是,调用myObject.method2
会给您undefined
。这是因为与this
一起使用的匿名函数中的setTimeout
并未引用myObject
,这取决于JavaScript解释器,它将指向不同的东西。但是,如果你有:
method2: function(){
var self = this;
setTimeout(function(){
alert( self.param );
},100);
}
这是有效的,因为当前状态this
- 在正确的位置 - 被捕获,并且将始终为可用的每个功能范围引用myObject
。
问题不仅限于使用setTimeout
。在任何你有匿名函数,子函数或闭包的地方,这个技巧都会派上用场。有时人们使用self
或that
或更具描述性的内容,具体取决于当前引用所代表的内容。
有一种替代方法可以使用self
或任何其他变量来记住"在任何特定点上的状态,那就是" bind"具有特定上下文的匿名或子函数。许多现代解释器现在支持Function.prototype.bind
方法,因此可以使用:
var method = function(){
console.log(this);
};
var methodWithWindow = method.bind(window);
var methodWithDocument = method.bind(document);
var methodWithObject = method.bind({random:"object"});
依次调用每个绑定方法将为您提供以下控制台输出:
Window
Document
Object {random:"object"}
如果您希望支持较旧的浏览器,可以使用polyfill,或者如果您更喜欢更简单的实现,也不必担心绑定参数。绑定代码的基础知识如下:
!Function.prototype.bind && (Function.prototype.bind = function(context){
var method = this;
return function(){
method.apply(context, arguments);
}
})
那么,初始示例如何使用bind?
method2: function(){
setTimeout((function(){
console.log(this); // `this` will be the same as the `this` passed to bind.
}).bind(this),100);
}
如上所示,一旦绑定,返回的函数(闭包)将保留指定的上下文;所以它可以在任何你想要的地方传递,并且仍然保持对你想要的对象的this
引用。这在method2
示例中非常有用,因为我们将方法与当前上下文捆绑在一起并将其传递给setTimeout
,后者将在稍后执行绑定方法(在我们退出当前块执行后很久)。 / p>
使用self
或任何其他变量时也会发生同样的情况。该变量将在函数的作用域链中捕获,并且在最终再次调用该函数时仍然可以进行访问。但是,使用bind
的好处是,如果您愿意,可以轻松覆盖上下文,您必须编写自己的特定方法来覆盖self
变量。
警告:值得注意的是,绑定函数时会返回一个新函数。如果将绑定函数与事件侦听器混合,然后尝试使用原始函数而不是绑定版本删除侦听器,则会导致混乱。
另外,因为绑定返回一个新函数,如果你绑定一个绑定函数,你实际上是在一个函数中包含一个函数,与另一个函数。您应该意识到这一点,因为它会影响性能,并且在避免内存泄漏方面会更难管理。我首选的绑定方法是使用带有自己解构方法的闭包(即依赖于self,但确保你有方法来消除它的内容),但这确实需要更多的前瞻性思维,并且在较小的时候不那么重要。 JS项目;或者一个关闭函数绑定 - 特别是如果绑定方法永远不会被任何引用捕获。
还值得一提的是,有时您可以在不使用bind
的情况下获得相同的结果,而是使用apply
- 这应该是您可以选择使用的任何内容。主要区别在于函数没有包含任何内容,而调用apply实际上在那里执行函数,然后使用不同的上下文 - 传递给apply的第一个参数。
var externalMethod = function(){
console.log(this); // will output myObject when called below
};
var myObject = {
method2: function(){
externalMethod.apply(this);
}
};
this
?在最近的评论被删除之前,只需详细说明this
的详细信息。 this
将引用四种内容之一,具体取决于您在其中使用它的功能的调用方式:
myObject.method()
以上将this
myObject
,除非method
已应用.bind(context)
操作。在这种情况下,this
将是最后绑定的上下文。
unattachedFunction()
除非this
已应用window
操作,否则将拥有unattachedFunction
全局上下文(通常在浏览器环境中为.bind(context)
)。在这种情况下,this
将是最后绑定的上下文。
anyFunction.apply(otherObject)
或
anyFunction.call(otherObject)
两者的this
总是otherObject
,因为以这种方式调用会覆盖任何绑定。
new myObject()
将this
引用myObject
的新实例,这将覆盖任何绑定。
考虑到以上所有因素,this
内的referencedMethod
会是什么?
var referencedMethod = myObject.method;
referencedMethod();
正确!这将是全球背景。这就是为什么如果你想与其他对象或代码共享方法 - 但仍然保留原始所有者作为上下文 - 你真的需要绑定,或保持与其所有者对象捆绑的功能,以便你可以调用或应用。
答案 1 :(得分:2)
答案 2 :(得分:1)
用于参考目的。 Javascript下的this
行为与其他语言不同。有关详细信息,请查看MDN Docs on this