ReferenceError: Недопустимая левая сторона в присваивании

мой код для игры с ножницами из каменной бумаги (под названием toss) выглядит следующим образом:

var toss = function (one,two) {
    if(one = "rock" && two = "rock") {
        console.log("Tie! Try again!");
    }
    // more similar conditions with `else if`
};

Когда я вхожу в параметры

toss("rock","rock")

Я получаю этот код ошибки:

"ReferenceError: Недопустимая левая сторона в назначении"

Как это исправить? Что означает эта ошибка и какие другие случаи, когда эта ошибка может произойти?

Ответ 1

Вы должны использовать == для сравнения (или даже ===, если вы хотите сравнить типы). Единственный = предназначен для назначения.

if (one == 'rock' && two == 'rock') {
    console.log('Tie! Try again!');
}

Ответ 2

Общие причины ошибки:

  • использование назначения (=) вместо равенства (==/===)
  • присвоение результата функции foo() = 42 вместо передачи аргументов (foo(42))
  • просто отсутствующие имена членов (т.е. предполагая выбор по умолчанию): getFoo() = 42 вместо getFoo().theAnswer = 42 или индексации массива getArray() = 42 вместо getArray()[0]= 42

В этом конкретном случае вы хотите использовать == (или лучше === - Что такое Type Coercion в Javascript?), чтобы проверить равенство (например, if(one === "rock" && two === "rock"), но фактическая причина, по которой вы получаете ошибку, сложнее.

Причиной ошибки является приоритет оператора. В частности, мы ищем && (приоритет 6) и = (приоритет 3).

Положим фигурные скобки в выражении в соответствии с приоритетом - && выше, чем =, поэтому он выполняется сперва аналогично тому, как можно было бы сделать 3+4*5+6 как 3+(4*5)+6:

 if(one= ("rock" && two) = "rock"){...

Теперь мы имеем выражение, подобное множеству присваиваний типа a = b = 42, которое из-за ассоциативности справа налево выполняется как a = (b = 42). Поэтому добавление большего количества фигурных скобок:

 if(one= (  ("rock" && two) = "rock" )  ){...

Наконец, мы пришли к реальной проблеме: ("rock" && two) не может быть оценен как l-значение, которое может быть присвоено (в этом конкретном случае это будет значение two как truthy).

Обратите внимание: если вы будете использовать фигурные скобки для соответствия воспринимаемому приоритету, окружающему каждое "равенство" с помощью фигурных скобок, вы не получите ошибок. Очевидно, что это также приводит к другому результату, чем вы ожидали, - изменяет значение обеих переменных, а не && на две строки "rock" && "rock", что приводит к тому, что "rock" (что в свою очередь является правдивым) все время из-за поведения логический &&:

if((one = "rock") && (two = "rock"))
{
   // always executed, both one and two are set to "rock"
   ...
}

Более подробную информацию об ошибке и других случаях, когда это может произойти, см. в спецификации:

Назначение

LeftHandSideExpression = AssignmentExpression
...
Выбросить исключение SyntaxError, если выполняются следующие условия:
...
IsStrictReference (lref) истинно

Левые выражения

и Тип ссылочной спецификации, объясняющий IsStrictReference:

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