考虑以下具有递归boom
函数
function foo() {
this.arr = [1, 2, 3, 4, 5];
this.output = "";
this.get_something = function(n, callback) {
this.output += "(" + n + ")";
$.get("...", function(result) {
// do something with 'result'
callback();
});
};
this.boom = function() {
if (this.arr.length > 0) {
this.get_something(this.arr.shift(), this.boom);
}
};
this.boom();
document.write("output = [" + this.output + "]");
}
var f = new foo();
第一次执行get_something
并调用callback()
时,this.arr
不再可用(可能因为this
现在指向其他内容)。< / p>
你会如何解决这个问题?
答案 0 :(得分:1)
当您从服务器接收数据后调用boom
时,您遇到的问题是函数调用上下文。将代码更改为此,事情应该开始工作:
this.get_something = function(n, callback) {
var context = this;
this.output += "(" + n + ")";
$.get("...", function(result) {
// do something with 'result'
callback.call(context);
});
};
我知道你的数组只有很少的项目,但你的这个代码可能只是一个例子,实际上有很多。问题是你的递归将与数组中的元素一样深。这可能会成为一个问题,因为浏览器(或更好的说它们中的Javascript引擎)会对递归深度进行安全检查,当你达到极限时会出现异常。
但是你还必须改变你的文档写入并把它放在繁荣功能中,因为这些调用现在不再是递归的(它们起初就是它们)。
this.boom = function() {
if (this.arr.length > 0) {
this.get_something(this.arr.shift(), this.boom);
}
else {
document.write("output = [" + this.output + "]");
}
};
您的代码实际上不会在递归中执行,除非您使用同步Ajax请求,它本身就是 show stopper ,并且每个人都会敦促您尽可能保持异步。因此,基本上我提供函数调用上下文的第一个解决方案就可以了。但/ / p>
如果您正在使用异步Ajax请求,则document.write
不应显示正确的结果,因为它会被过早调用。我上次建议的boom
函数体也可以解决这个问题。
答案 1 :(得分:1)
this.get_something(this.arr.shift(), this.boom.bind(this));
现在您已将this
绑定为this
。 boom
函数中的上下文将始终符合您的预期。
.bind
,因此请使用compatibility implementation。
旁注$.proxy
可以完成.bind
提供的大部分内容。因此,使用
this.get_something(this.arr.shift(), $.proxy(this.boom.bind, this));
IE9,FF4和Chrome .bind
为currently supported。