admin管理员组

文章数量:1302403

I am trying to validate a prompt in a JavaScript main function. Basically it asks for a number between 10 and 20. If the value does not fall within that range or is not a number, it should give an error message and ask again. If 0 is entered or the cancel button is pressed it should stop the routine pletely.

I know this is pretty bad code, but it works for me perfectly.

The problem I am having is when I try to validate it in JSLint I get the following error:

Expected 'else { if' and instead saw 'else if'.
        } else if (amtEntered >= 10 && amtEntered <=20) {

If I unment the return 0 statement, the error is gone.

var amt;    
var inputError = false;

do {
    if (inputError) {
        alert ("You have entered an error. \n Please try again.");
    }
    amt = prompt("Enter amount between 10 and 20: ","");
    amt = Number(amt);
    if (isNaN(amt)) {
        inputError = true;
    } else if (amt === null || amt === 0) {
        // If amt is blank or cancel button pressed then exit loop and exit function.
        inputError = false;
        return 0;
    } else if (amt >= 10 && amt <=20) {
        inputError = false;
    } else {
        inputError = true;
    }
}
while (inputError);

Would appreciate any tips or remendations on fixing this piece of code.

I am trying to validate a prompt in a JavaScript main function. Basically it asks for a number between 10 and 20. If the value does not fall within that range or is not a number, it should give an error message and ask again. If 0 is entered or the cancel button is pressed it should stop the routine pletely.

I know this is pretty bad code, but it works for me perfectly.

The problem I am having is when I try to validate it in JSLint I get the following error:

Expected 'else { if' and instead saw 'else if'.
        } else if (amtEntered >= 10 && amtEntered <=20) {

If I unment the return 0 statement, the error is gone.

var amt;    
var inputError = false;

do {
    if (inputError) {
        alert ("You have entered an error. \n Please try again.");
    }
    amt = prompt("Enter amount between 10 and 20: ","");
    amt = Number(amt);
    if (isNaN(amt)) {
        inputError = true;
    } else if (amt === null || amt === 0) {
        // If amt is blank or cancel button pressed then exit loop and exit function.
        inputError = false;
        return 0;
    } else if (amt >= 10 && amt <=20) {
        inputError = false;
    } else {
        inputError = true;
    }
}
while (inputError);

Would appreciate any tips or remendations on fixing this piece of code.

Share asked Sep 12, 2014 at 2:17 RickRick 2,30819 gold badges67 silver badges104 bronze badges 3
  • 4 Your code is fine...it is JSLint that is super strict/picky...for a more forgiving but still-useful lint try: javascriptlint./online_lint.php – The One and Only ChemistryBlob Commented Sep 12, 2014 at 2:21
  • If we're going to nitpick why didn't you write amt === null as !amt ? – The One and Only ChemistryBlob Commented Sep 12, 2014 at 2:31
  • Comment out the return 0; line and the message goes away. Looks like the return kicks in the use_nested_if option of JSLint – Paul S. Commented Sep 12, 2014 at 2:38
Add a ment  | 

4 Answers 4

Reset to default 5

Well, you could fix it by changing your if statement to:

if (isNaN(amt)) {
    inputError = true;
} else {
    if (amt === null || amt === 0) {
        // If amt is blank or cancel button pressed then exit loop and exit function.
        inputError = false;
        return 0;
    } else {
        if (amt >= 10 && amt <=20) {
            inputError = false;
        } else {
            inputError = true;
        }
    }
}

But I think this is just JSLint being pedantic. What you have is actually valid syntax.


I believe the reason JSLint plains about things like this may be if you have code like:

if (condition)
    do_something();

and someone later changes it to:

if (condition)
    do_something();
    do_something_else();

Without the braces, that code isn't going to work as expected. Whether you consider that a good enough reason to pepper your code with more braces is mostly a matter of style.

This particular case is plicated by the fact that it only happens when the return statement is there, so the reasoning is more plex.

Looking at the source code, it appears to load up the entire if block (the true branch) then check if the next token is else. If the if block has a disruptor (such as return), it plains about an unnecessary else (if the next token is else) or lack of braces (if the next token set is else if):

stmt('if', function () {
    var paren = next_token;
    one_space();
    advance('(');
    step_in('control');
    no_space();
    edge();
    this.arity = 'statement';
    this.first = expected_condition(expected_relation(expression(0)));
    no_space();
    step_out(')', paren);
    one_space();
    this.block = block('if');
    if (next_token.id === 'else') {
        if (this.block.disrupt) {
            next_token.warn(this.elif ? 'use_nested_if' : 'unnecessary_else');
        }
        one_space();
        advance('else');
        one_space();
        if (next_token.id === 'if') {
            next_token.elif = true;
            this.else = statement(true);
        } else {
            this.else = block('else');
        }
        if (this.else.disrupt && this.block.disrupt) {
            this.disrupt = true;
        }
    }
    return this;
});

The unnecessary_else is easy to figure out, it's to catch things like:

if (condition) {
    return 0;
} else {
    do_something();
}

In that case, it's better written as:

if (condition) {
    return 0;
}
do_something();

The use_nested_if is more interesting in that, if braces are a good idea, they should be used all the time, not just when the block has a return statement. I'm not sure why the author decided this was only a problem when a block returned.

If it really bothered you, you could no doubt modify the code to remove that check, not something I'd do lightly. Perhaps it may be better to ask the author to add the tolerate_non_nested_if option to the software. Or, you could just ignore the warnings if you know it's okay.


And, on further reflection, it may be that the same reasoning is being used for both warnings - if you have an if block that returns, any code after that should not be in the equivalent else block, it should be stand-alone (but in the context of any outer if/else blocks of course).

By that I mean you could probably use:

if (isNaN(amt)) {
    inputError = true;
} else {
    if (amt === null || amt === 0) {
        // If amt is blank or cancel button pressed then exit loop and exit function.
        inputError = false;
        return 0;
    } // no else needed here.
    if (amt >= 10 && amt <=20) {
        inputError = false;
    } else {
        inputError = true;
    }
}

Ok, two issues, I think, if you let the double var declaration and the alert and prompt slip by. (I've "fixed" the vars by bining into one, added a jslint directive of browser:true, and added window before the alert and prompt, below.)

First, if you're literally using the code you've got above (and not checking it in the context of more code), you've got a return outside of a function, which is a little wacky. So I've added wrapMe() to wrap it so that JSLint stops getting confused by the return, otherwise you get an unexpected return error even after the block disruption stuff mentioned below.

Second, it is the return, or, more specifically, the "block.disrupt" (link is to JSLint's code as of today) that's upsetting JSLint.

Crockford wants you to immediately stop the block if you're returning. No sense (in JSLint's mind) in else after a return. That block can be pulled out of the if branching. That is, to JSLint, any code after a block containing a conditional disruption already is inherently an else equivalency, and to include the else is misleading -- again, in a JSLintian sense.

You get the point in any event. You need to pull the else after the block.disrupt out, close out the if that includes the disruption, and start a new statement.

Note that disrupt could also be a break, for instance. So if you had your original code and substituted a break; for return 0;, you'd get the same admittedly somewhat misleading error. (And then you wouldn't have to wrap in a function.)

So the below is equivalent code to what you initially had in a format JSLint likes -- I believe. I'm a little tired.

/*jslint sloppy:true, white:true, browser:true */

function wrapMe()   {
    var amt, inputError = false;

    do {
        if (inputError) {
            window.alert ("You have entered an error. \n Please try again.");
        }
        amt = window.prompt("Enter amount between 10 and 20: ","");
        amt = Number(amt);
        if (isNaN(amt)) {
            inputError = true;
        } else {
            if (amt === null || amt === 0) {
                // If amt is blank or cancel button pressed then exit loop and exit function.
                inputError = false;
                return 0;  // BLOCK DISRUPTION!!! (Not sure why that felt Scott Pilgrim-y)
            } 
            // If no disruption, continue.
            if (amt >= 10 && amt <=20) {
                inputError = false;
            } else {
                inputError = true;
            }
        }
    }
    while (inputError);
}

So instead of else if-ing after a block disruption, just use a new if.

JSLint is being picky about your code, which is valid, but (in my opinion) has a very odd structure. Consider a design like this instead

var amt,
    fail = true;
// would use `while (amt = prompt("Enter amount between 10 and 20: ", ""))` personally
amt = prompt("Enter amount between 10 and 20: ", "");
while (amt) {
    amt = +amt; // to Number
    if (10 <= amt && amt <= 20) {
        fail = false;
        break;
    }
    alert("You have entered an error. \n Please try again.");
    amt = prompt("Enter amount between 10 and 20: ", "");
}
if (fail) {
    return 0;
}

It could have something to do with the return 0;; an else isn’t needed when that condition has been reached. Of course, since the return is in an else if, the fix is less straightforward, and the suggested fix doesn’t really make much sense.

Luckily, you can simplify!

var amt;
var inputError = false;

while (true) {
    if (inputError) {
        alert ("You have entered an error. \n Please try again.");
    }

    inputError = true;

    amt = prompt("Enter amount between 10 and 20: ");

    if (!amt) {
        return;
    }

    amt = Number(amt);

    if (isNaN(amt)) {
        continue;
    }

    if (amt >= 10 && amt <= 20) {
        break;
    }
}

… assuming you have enough checks to warrant not just doing this:

if (!amt) {
    return;
}

amt = +amt;
inputError = !(amt >= 10 && amt <= 20); // NaN will always pare as false here

本文标签: javascriptJSLint Expected 39elseif39 and instead saw 39else ifStack Overflow