为什么“this”指向Javascript递归函数中的其他东西?

时间:2011-06-07 11:12:47

标签: javascript jquery

考虑以下具有递归boom函数

的JavaScript代码
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>

你会如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

问题出在Ajax请求和函数调用上下文

当您从服务器接收数据后调用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绑定为thisboom函数中的上下文将始终符合您的预期。

非现代浏览器不支持

.bind,因此请使用compatibility implementation

旁注$.proxy可以完成.bind提供的大部分内容。因此,使用

可能更简单
this.get_something(this.arr.shift(), $.proxy(this.boom.bind, this));
IE9,FF4和Chrome

.bindcurrently supported

.bindjQuery.proxy