最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

forms - Javascript reference in loop: "Uncaught TypeError: Cannot read property 'value' of undefined&am

matteradmin7PV0评论

I tried debugging my code for like a few hour but I got nothing out of it. The issue is that it makes absolutely no sense on why it reports an error every time I tried to use document.forms[0][i] (i as the iterator) in the event listener but "this" satisfies the code.

//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);
            });
        }
    }
};

Wouldn't "this" refer to document.forms[0][i]?... formFields references to document.forms[0]. However the exact same code (with "this" where formFields[i] is at) works just fine.

Here is the demo: /

I tried debugging my code for like a few hour but I got nothing out of it. The issue is that it makes absolutely no sense on why it reports an error every time I tried to use document.forms[0][i] (i as the iterator) in the event listener but "this" satisfies the code.

//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);
            });
        }
    }
};

Wouldn't "this" refer to document.forms[0][i]?... formFields references to document.forms[0]. However the exact same code (with "this" where formFields[i] is at) works just fine.

Here is the demo: http://jsfiddle/PbHwy/

Share Improve this question edited Jun 16, 2012 at 8:24 Codist asked Jun 16, 2012 at 8:13 CodistCodist 1,2082 gold badges12 silver badges29 bronze badges 2
  • Please post the exact error message. It also helps if you provide a little demo. You can use http://jsfiddle for this. – Zeta Commented Jun 16, 2012 at 8:17
  • When the onblur event occurs on the form field... Here is the error that pops up in the dev console "Uncaught TypeError: Cannot read property 'value' of undefined". – Codist Commented Jun 16, 2012 at 8:19
Add a ment  | 

3 Answers 3

Reset to default 3

Cranio's answer already contains the root of the matter. To get rid of this you can either include formFields[i] by using closures

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]);
*/

or simply using this.

See also:

  • MDN: Creating closures in loops: A mon mistake

Because you define formFields in a scope outside (or better, different than) the event listener. When the event listener is called, it is called not in the addListeners function where you define formFields, but "independently", so the reference is lost and its value is undefined (but this works because it is not dependent on that scope).

The problem is that the variable i (referred to in each of your handlers) is the exact same variable in each of them, which by the time the loop has finished has value formFields.length+1 and is therefore wrong for all of them. Try this instead [note: the below used to say something VERY WRONG before I edited it -- thanks to Zeta for pointing out my mistake]:

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);
            });
        }
    }
};

and you'll find it works (unless there's another bug that I haven't noticed).

If you can afford to support only Javascript 1.7 and above, you can instead write your old code but make your for look like this: for (let i=0; i<formFields.length; i++). But you quite possibly can't.

Articles related to this article

Post a comment

comment list (0)

  1. No comments so far