3

我尝试调试我的代码几个小时,但我什么也没得到。问题是,为什么每次我尝试在事件侦听器中使用 document.forms[0][i] (i 作为迭代器)但“this”满足代码时它报告错误是绝对没有意义的。

//broken
var addListeners = function() {
    var i;
    var formFields = document.forms[0];
    var formSubmit = formFields["submit"];

    for (i = 0; i < formFields.length; i++) {
        if (formFields[i] != formSubmit) {
            formFields[i].onblur = (function () {
                checkNonEmpty(formFields[i]);
            });
        }
    }
};

//works
var addListeners = function() {
    var i;
    var formFields = document.forms[0];
    var formSubmit = formFields["submit"];

    for (i = 0; i < formFields.length; i++) {
        if (formFields[i] != formSubmit) {
            formFields[i].onblur = (function () {
                checkNonEmpty(this);
            });
        }
    }
};

“this”不是指 document.forms[0][i] 吗?... formFields 对 document.forms[0] 的引用。然而,完全相同的代码(在 formFields[i] 所在的“this”处)工作得很好。

这是演示:http: //jsfiddle.net/PbHwy/

4

3 回答 3

3

因为您formFields在事件侦听器之外(或更好,不同)的范围内定义。调用事件侦听器时,它不是在addListeners您定义的函数中调用formFields,而是“独立”调用,因此引用丢失并且其值未定义(但this可以工作,因为它不依赖于该范围)。

于 2012-06-16T08:17:35.610 回答
3

克拉尼奥的回答已经包含了问题的根源。要摆脱这种情况,您可以formFields[i]使用闭包来包含

var blurCallbackGenerator = function(element){
    return function () {
        checkNonEmpty(element);
    };
};
formFields[i].onblur = blurCallbackGenerator(formFields[i]);

/* // dense version:
formFields[i].onblur = (function(element){
    return function () {
        checkNonEmpty(element);
    };
})(formFields[i]);
*/

或简单地使用this.

也可以看看:

于 2012-06-16T08:24:06.737 回答
1

问题是变量i(在您的每个处理程序中引用)在每个处理程序中都是完全相同的变量,当循环完成时,它具有值formFields.length+1,因此对所有处理程序都是错误的。试试这个[注意:在我编辑之前,下面的内容曾经说过一些非常错误的东西——感谢 Zeta 指出我的错误]:

var addListeners = function() {
    var i;
    var formFields = document.forms[0];
    var formSubmit = formFields["submit"];

    for (i = 0; i < formFields.length; i++) {
        if (formFields[i] != formSubmit) {
            formFields[i].onblur = (function(j) {
                return (function () {
                    checkNonEmpty(formFields[j]);
                })(i);
            });
        }
    }
};

你会发现它有效(除非有另一个我没有注意到的错误)。

如果您负担得起仅支持 Javascript 1.7 及更高版本,则可以改为编写旧代码,但让您的代码for看起来像这样:for (let i=0; i<formFields.length; i++). 但你很可能做不到。

于 2012-06-16T08:20:14.127 回答