Многократное левостороннее назначение с JavaScript


186
var var1 = 1,
    var2 = 1,
    var3 = 1;

Это эквивалентно этому:

var var1 = var2 = var3 = 1;

Я вполне уверен, что это порядок, в котором определены переменные: var3, var2, var1, что будет эквивалентно следующему:

var var3 = 1, var2 = var3, var1 = var2;

Есть ли способ подтвердить это в JavaScript? Возможно, вы используете какой-нибудь профилировщик?


6
НАЗНАЧЕНИЕ ПРОИСХОДИТ ОТ ПРАВА НА ЛЕВЫЙ приоритет оператора javascript
neaumusic

это также применимо, если я использую this.var1 = this.var2 = this.var3 = 1?
Gangadhar JANNU

Ответы:


404

Фактически,

var var1 = 1, var2 = 1, var3 = 1;

это не эквивалентно:

var var1 = var2 = var3 = 1;

Разница в определении объема:

function good() {
  var var1 = 1, var2 = 1, var3 = 1;
}

function bad() {
  var var1 = var2 = var3 = 1;
}

good();
console.log(window.var2); // undefined

bad();
console.log(window.var2); // 1. Aggh!

На самом деле это показывает, что назначение правильно ассоциативно. badПример эквивалентен:

var var1 = (window.var2 = (window.var3 = 1));

44
Черт, это неожиданно. Спасибо за совет, я буду следить за этим.
Дэвид Калхоун

10
@ SkinnyG33k, потому что это справа налево. так что он будет разбирать самое правое перед самым левым. так var var1=var2бывает после var3 = 1и после var2 = var3. это какvar3=1; var2=var3; var var1=var2
gcb

12
Просто чтобы заметить: если вы знаете, что хотите сделать что-то подобное заранее, вы все равно можете отделить определение от назначения. Итак: var v1, v2, v3;потом, позже: v1 = v2 = v3 = 6;они все еще будут в местном масштабе. Так как Дэвид упомянул оповещения, это будет работать так, как ожидалось (если предварительная версия):alert(v1 = v2 = v3 = 6);
ShawnFumo

3
Именно. Но если мы будем следовать некоторым распространенным лучшим практикам, в этом случае, объявив наши переменные наверху, мы сможем избежать нежелательных ошибок и избежать утечки локальных переменных в глобальную область. Смотрите: jsfiddle.net/gleezer/r9Mu8/1
Nobita

1
«Черт, это неожиданно». Почему это было бы неожиданно? Большинство языков требуют, чтобы вы объявили переменные перед использованием. JavaScript ничем не отличается, если вы не объявляете свою переменную, по умолчанию используется глобальный объект окна. Начните использовать «строгий» в своем JavaScript, и вы станете лучшим программистом JavaScript.
cchamberlain

20

Назначение в JavaScript работает справа налево. var var1 = var2 = var3 = 1;,

Если значение любого из этих переменных 1после этого заявления, то логически должны начать с правой стороны , в противном случае значения или var1и var2будет неопределенное.

Вы можете думать об этом как эквивалент var var1 = (var2 = (var3 = 1)); где сначала оценивается самый внутренний набор скобок.


1
Спасибо, это определенно помогает. Это помогает подумать о том, какие ошибки будут выброшены, если бы они оценивались не справа налево (в этом случае ошибка будет заключаться в том, что var1 / var2 не определены).
Дэвид Калхоун

5
Это на самом деле синтаксическая ошибка. Вы не можете иметь (сразу после var. Удаление внешнего набора скобок позволяет его компилировать без ошибок var var1 = (var2 = (var3 = 1));. В то время я чувствовал, что это не вполне иллюстрирует ситуацию, но я полагаю, это то же самое.
Джастин Джонсон

var var1 = var2 = var3 = 1;. равно var var3 = 1; var var2 = var3; var var1 = var2;
xgqfrms

8

var var1 = 1, var2 = 1, var3 = 1;

В этом случае varключевое слово применимо ко всем трем переменным.

var var1 = 1,
    var2 = 1,
    var3 = 1;

что не эквивалентно этому:

var var1 = var2 = var3 = 1;

В этом случае varключевое слово « позади экрана» применимо только к тому, что происходит var1из-за подъема переменных, а остальная часть выражения оценивается нормально, поэтому переменные var2, var3становятся глобальными.

Javascript обрабатывает этот код в следующем порядке:

/*
var 1 is local to the particular scope because of var keyword
var2 and var3 will become globals because they've used without var keyword
*/

var var1;   //only variable declarations will be hoisted.

var1= var2= var3 = 1; 

8
a = (b = 'string is truthy'); // b gets string; a gets b, which is a primitive (copy)
a = (b = { c: 'yes' }); // they point to the same object; a === b (not a copy)

(a && b)логически (a ? b : a)и ведет себя как умножение (например. !!a * !!b)

(a || b)логично (a ? a : b)и ведет себя как сложение (например. !!a + !!b)

(a = 0, b)это сокращение от "не заботиться", если aэто правда, неявно вернутьb


a = (b = 0) && "nope, but a is 0 and b is 0"; // b is falsey + order of operations
a = (b = "b is this string") && "a gets this string"; // b is truthy + order of ops

Приоритет оператора JavaScript (порядок операций)

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


В конце концов, вам могут понадобиться «thunks», а не жестко закодированные значения, и для меня thunk - это и функция, и результирующее значение (одно и то же «вещь»).

const windowInnerHeight = () => 0.8 * window.innerHeight; // a thunk

windowInnerHeight(); // a thunk

4

Попробуй это:

var var1=42;
var var2;

alert(var2 = var1); //show result of assignment expression is assigned value
alert(var2); // show assignment did occur.

Обратите внимание на единственное «=» в первом предупреждении. Это покажет, что результатом выражения присваивания является присвоенное значение, а во 2-м предупреждении будет показано, что назначение произошло.

Логично следует, что назначение должно быть связано справа налево. Однако, поскольку это все атомарно для javascript (нет многопоточности), конкретный движок может по-настоящему оптимизировать его немного по-другому.


1
Спасибо за ответ. Я думаю, что искал способ использовать оповещения при сохранении структуры множественных назначений (a = b = c), но я не думаю, что это возможно.
Дэвид Кэлхун

1
Отдельные утверждения, подобные этому в javascript (и, хотя несколько выражений, которые все работают в одном утверждении), можно считать атомарными. Вы должны разбить это.
Джоэл Коухорн

1

К настоящему времени ясно, что они не одинаковы. Способ кодирования это

var var1, var2, var3
var1 = var2 = var3 = 1

А как насчет пусть назначения? Точно так же, как var, не позволяйте заданию let сбить вас с толку из-за объема блока.

let var1 = var2 = 1 // here var2 belong to the global scope

Мы могли бы сделать следующее:

let v1, v2, v3
v1 = v2 = v3 = 2

Примечание: кстати, я не рекомендую использовать несколько назначений, даже не несколько объявлений в одной строке.


-3

coffee-script может сделать это с апломбом ..

for x in [ 'a', 'b', 'c' ] then "#{x}" : true

[ { a: true }, { b: true }, { c: true } ]


7
Это на самом деле не отвечает на вопрос. Пожалуйста, перечитайте вопрос.
Мартин

30
кто заботится о coffeescript
neaumusic
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.