Что не так с определением переменных JavaScript в блоках if?

у меня есть такой код:

if (condition) {
var variable = blah;
}

if (differentcondition) {
var variable = blah;
}

это правильно?

Я предполагаю, что переменная не будет назначена, если условие не возвращает true.

JSLint продолжает говорить мне, переменная уже определена.

Я делаю это неправильно?

спасибо.

хорошо, вот мой фактический usecase, я делаю делегирование событий следующим образом:

$("#container").click(function (event){ 

    if ($(event.target).is('img.class1')) {
        var imagesrc = $(event.target).attr('src');
        // Do something with imagesrc
    }

    if ($(event.target).is('img.class2')) {
        var imagesrc = $(event.target).attr('src');
        // Do something with imagesrc
    }

    // This condition is mutually exclusive to the above 2
    if ($(event.target).is('img.class3')) {
        var imagesrc = $(event.target).attr('src');
        // Do something with imagesrc
    }

    // This condition is mutually exclusive to 1 and 2 but not to 3
    if ($(event.target).is('img.class4')) {
        var imagesrc = $(event.target).attr('src');
        // Do something with imagesrc
    }

});

На самом деле эти 2 класса не взаимно эксклюзивный.

это работает для меня, но правильно ли это?

ответы были очень информативными, но я все еще не понимаю, как я должен настроить переменные здесь.

Как я должен структурировать это?

Я, вероятно, должен был использовать этот пример с самого начала.

5 ответов


потому что javascript имеет что-то под названием "подъем", что заставляет ваш код делать то, что он не выглядит так, как он должен делать. В принципе, это означает, что интерпретатор javascript переместит все объявления var, независимо от того, где они находятся в теле функции, в верхнюю часть тела функции. Затем он переместит все определения функций наверх, как раз под всеми vars. Затем он завершит компиляцию функции.

положить var внутри оператора if не против "правила" языка, но это означает, что из-за подъема var этот var будет определен независимо от того, выполняется ли условие оператора if.

имейте в виду также, что подъем не включает назначение, так как другие указали, объявления var будут перемещены наверх и оставлены неопределенными, пока они не будут назначены позже.

Это пример функции, которая должна была казаться хорошей идеей в то время, но она оказалась быть более запутанным, чем полезным.


это потому, что в JavaScript переменные имеют разную область действия только в функциональных блоках. В отличие от других языков, if-blocks не имеют другой области в JavaScript.

в вашем случае JSLint скажет вам, что переменная уже определена, потому что возможно, что оба условия истинны, и в этом случае вы перезаписываете свои переменные.

вот пример того, как области работают в JavaScript:

function Something() {
    var thing1 = "hello";

    (function() {
        var thing2 = "world";
    })();

    // This line will throw a ReferenceError because "thing2" is not defined in this scope
    // It only exists within the scope of the function executed above
    alert(thing1 + thing2);
}

function SomethingElse() {
    var thing1 = "hello";

    if(true) {
        var thing2 = "world";
    }

    // This line will work because thing2 is not limited to the if-block
    alert(thing1 + thing2);
}

только функции создают внутреннюю область. Он становится еще более волосатым, как в этом примере.

var x = 2;
function foo() {
    alert(x); // will alert undefined?!?

    var x = 4;
}
foo();
alert(x); // will alert 2

первое предупреждение фактически скажет undefined. Почему? Потому что все инициализации переменных, которые происходят в функции, инициализируются до undefined в начале функции. Вот почему Крокфорд говорит инициализировать все переменные как можно раньше.

Так что ваш код, вероятно, должен выглядеть так:

$("#container").click(function (event){ 
        var imagesrc;
        if ($(event.target).is('img.class1')) {
                imagesrc = $(event.target).attr('src');
                // Do something with imagesrc
        }

        if ($(event.target).is('img.class2')) {
                imagesrc = $(event.target).attr('src');
                // Do something with imagesrc
        }

        // This condition is mutually exclusive to the above 2
        if ($(event.target).is('img.class3')) {
                imagesrc = $(event.target).attr('src');
                // Do something with imagesrc
        }

        // This condition is mutually exclusive to 1 and 2 but not to 3
        if ($(event.target).is('img.class4')) {
                imagesrc = $(event.target).attr('src');
                // Do something with imagesrc
        }

});

являются ли два if-условия взаимоисключающими? Возможно, вы хотите использовать структуру управления "else":

if (condition) {
    var variable = blah;
}
else if (differentcondition) {
    var variable = blah;
}

это означает, что если первое условие истинно, то вторая часть кода никогда не будет выполнена.

В общем случае лучше объявить переменные в структуре, в которой они используются. Если переменная должна существовать только в операторе if, объявив ее там, в противном случае переместите ее наружу, как Итак:

var variable;
if (condition) {
    variable = blah;
}
else if (differentcondition) {
    variable = blah;
}
// continue to use variable here...

Примечание: Если вы используете отдельный ifs без else, то вам нужно сначала установить переменную в значение по умолчанию.


как я должен структурировать это?

в этом случае, похоже, было бы лучше вложить условия:

$("#container").click(function (event) {
    if ($(event.target).is('img')) {
        var imagesrc = $(event.target).attr('src');

        if ($(event.target).is('.class1')) {
            // Do something with imagesrc
        }

        if ($(event.target).is('.class2')) {
            // Do something with imagesrc
        }

        // This condition is mutually exclusive to the above 2
        if ($(event.target).is('.class3')) {
            // Do something with imagesrc
        }

        // This condition is mutually exclusive to 1 and 2 but not to 3
        if ($(event.target).is('.class4')) {
            // Do something with imagesrc
        }
    }
});

или еще лучше использовать делегирование событий jQuery:

$("#container").on("click", "img", function (event) {
    var imagesrc = $(this).attr('src');

    if ($(this).is('.class1')) {
        // Do something with imagesrc
    }

    if ($(this).is('.class2')) {
        // Do something with imagesrc
    }

    // This condition is mutually exclusive to the above 2
    if ($(this).is('.class3')) {
        // Do something with imagesrc
    }

    // This condition is mutually exclusive to 1 and 2 but not to 3
    if ($(this).is('img.class4')) {
        // Do something with imagesrc
    }
});