在JavaScript中,我知道闭包可以定义为一个嵌套函数,可以访问其包含函数的变量。例如:
function outerFunction(x, y) {
function innerFunction() {
return x + y + 10;
}
return innerFunction;
}
现在,以下代码连接了请求对象的onreadystatechange
属性的回调;然而,我想知道,根据定义,这是否也被视为关闭:
/* This is a contrived example, I know.
* Bear with me - it demonstrates the point I'm trying to convey. */
function submitHandler() {
var oRequest = createRequest(); // assume I'm getting an instance of the xhr
var sUsername = 'Tom'; // assume this is needed for work in the handler
var This = this;
oRequest.onreadystatechange = function() {
This.handleResponse(oRequest, sUsername)
}
}
function handleResponse(oResponse, sUsername) {
if(oResponse.readyState === 4 && oResponse.status === 200) {
// do work with the username
} else {
// we're not done yet...
}
}
我意识到handleResponse
函数也可以在submitHandler
的上下文中作为匿名函数编写,但我发现如果回调是更复杂的Ajax代码可以更容易阅读和维护在函数范围之外定义回调它们。再一次,这是一个人为的例子,我希望只是简单地说明我的问题。
答案 0 :(得分:3)
是的,根据定义你假设它是一个闭包是正确的。
听起来你知道你的东西,但here is a good, extensive article on javascript closures。
答案 1 :(得分:3)
我完全同意太多的内联闭包函数不会增强可读性。另一方面,我强烈不喜欢编写闭包的var self = this
样式,this
只是一个变体,因为它在声明中仍然过于冗长,并且你引入了自己的新'关键字',无论是是this
或self
。
你想要的是咖喱/绑定方法。
function $A(o)
{
var a = [];
for (var i = 0; i < o.length; ++i)
a.push(o[i]);
return a;
}
Function.prototype.bind = function()
{
var _method = this;
var a = $A(arguments)
var o = a.shift();
return function()
{
return _method.apply(o, a.concat($A(arguments)));
}
}
Function.prototype.curry = function()
{
var _method = this;
var a = $A(arguments);
return function()
{
return _method.apply(null, a.concat($A(arguments)));
}
}
这些方法来自Prototype库。我甚至在不使用Prototype库的项目中使用它们,因为它们非常有用!
在你的情况下,这意味着而不是写作:
var This = this;
oRequest.onreadystatechange = function() {
This.handleResponse(oRequest, sUsername)
}
你现在可以写:
oRequest.onreadystatechange = this.handleResponse.curry(oRequest,sUsername);
但是,如果您想转移此关键字的含义,则可以执行此操作
oRequest.onreadystatechange = this.handleResponse.bind(this,oRequest,sUsername);
handleResponse
在被调用时,将与this
具有相同的submitHandler
上下文。
答案 2 :(得分:1)
你的第一个例子不是封闭。如果您返回了innerFunction,但是您正在执行innerFunction并返回结果。
第二个例子有效并正在使用闭包。使用这种特定技术的一个警告是,在某些浏览器实现中可能会导致非常严重的内存泄漏(IE当然也可能是其他浏览器)。您将在oRequest中保存的xhr,引用函数的onreadystatechange和作为xhr所在范围的函数作用域之间创建循环引用。 xhr不仅会保留在内存中,因此响应也会很大(特别是如果是XML)可以快速吞噬内存。
在处理响应期间将onreadystatechange属性设置为空的全局级别函数。这将打破这个圈子。