Múltipla atribuição à esquerda com JavaScript


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

Isso é equivalente a isso:

var var1 = var2 = var3 = 1;

Estou bastante certo de que esta é a ordem em que as variáveis ​​são definidas: var3, var2, var1, que seria equivalente a isso:

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

Existe alguma maneira de confirmar isso em JavaScript? Usando algum profiler possivelmente?


6
ATRIBUIÇÃO ACONTECE DIREITO À ESQUERDA precedência do operador javascript
neaumusic

isso também é aplicável se eu usar this.var1 = this.var2 = this.var3 = 1?
Gangadhar JANNU

Respostas:


404

Na realidade,

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

não é equivalente a:

var var1 = var2 = var3 = 1;

A diferença está no escopo:

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!

Na verdade, isso mostra que a atribuição é correta associativa. O badexemplo é equivalente a:

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

44
Caramba, isso é inesperado. Obrigado pela dica, vou cuidar disso.
David Calhoun

10
@ SkinnyG33k porque é da direita para a esquerda. então ele analisará a direita mais antes da esquerda. assim var var1=var2acontece depois var3 = 1e depois var2 = var3. é comovar3=1; var2=var3; var var1=var2
gcb 29/01

12
Apenas para observar: se você sabe que deseja fazer esse tipo de coisa com antecedência, ainda pode interromper a definição da tarefa. Então: var v1, v2, v3;Mais tarde: v1 = v2 = v3 = 6;eles ainda estarão no escopo local. Desde que David mencionou alertas, isso funcionaria conforme o esperado (se pré-definido):alert(v1 = v2 = v3 = 6);
ShawnFumo

3
Exatamente. Porém, se seguirmos algumas práticas recomendadas comuns, nesse caso, declarando nossas variáveis ​​no topo, podemos evitar erros indesejados e evitar que variáveis ​​locais vazem para o escopo global. Veja: jsfiddle.net/gleezer/r9Mu8/1
Nobita

1
"Caramba, isso é inesperado." Por que isso seria inesperado? A maioria dos idiomas exige que você declare suas variáveis ​​antes do uso. JavaScript não é diferente, se você deixar de declarar sua variável, o padrão será o objeto de janela global. Comece a usar 'use strict' no seu javascript e você se tornará um programador JavaScript melhor.
Cchamberlain 31/03

19

A atribuição em javascript funciona da direita para a esquerda. var var1 = var2 = var3 = 1;.

Se o valor de qualquer uma dessas variáveis ​​estiver 1após essa instrução, logicamente ele deve ter começado da direita, caso contrário, o valor ou var1e var2seria indefinido.

Você pode pensar nisso como equivalente a var var1 = (var2 = (var3 = 1));onde o conjunto de parênteses mais interno é avaliado primeiro.


1
Obrigado, isso definitivamente ajuda. Ajuda pensar em termos de quais erros seriam gerados se fossem avaliados de maneira diferente da direita para a esquerda (nesse caso, o erro seria que var1 / var2 são indefinidos).
David Calhoun

5
Na verdade, é um erro de sintaxe. Você não pode ter (imediatamente depois var. A remoção do conjunto externo de parênteses permite compilar sem erros var var1 = (var2 = (var3 = 1));,. Na época, senti que isso não ilustrava bem o ponto, mas acho que é o mesmo.
Justin Johnson

var var1 = var2 = var3 = 1;. igual a var var3 = 1; var var2 = var3; var var1 = var2;
xgqfrms 19/08/19

8

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

Nesse caso, a varpalavra-chave é aplicável a todas as três variáveis.

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

o que não é equivalente a isso:

var var1 = var2 = var3 = 1;

Nesse caso, a varpalavra-chave por trás das telas é aplicável apenas a var1içamento devido a variáveis ​​e o restante da expressão é avaliado normalmente para que as variáveis var2, var3se tornem globais

O Javascript trata esse código nesta ordem:

/*
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)é logicamente (a ? b : a)e se comporta como multiplicação (por exemplo !!a * !!b)

(a || b)é logicamente (a ? a : b)e se comporta como adição (por exemplo !!a + !!b)

(a = 0, b)é uma abreviação de não se importar se afor verdade, retorne implicitamenteb


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

Precedência do operador JavaScript (ordem das operações)

Observe que o operador de vírgula é realmente o operador menos privilegiado, mas os parênteses são os mais privilegiados e andam de mãos dadas ao construir expressões de uma linha.


Eventualmente, você pode precisar de 'thunks' em vez de valores codificados e, para mim, um thunk é a função e o valor resultante (a mesma 'coisa').

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

windowInnerHeight(); // a thunk

4

Tente o seguinte:

var var1=42;
var var2;

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

Observe o único '=' no primeiro alerta. Isso mostrará que o resultado de uma expressão de atribuição é o valor atribuído, e o segundo alerta mostrará que a atribuição ocorreu.

Segue-se logicamente que a atribuição deve ter sido encadeada da direita para a esquerda. No entanto, como tudo é atômico para o javascript (não há encadeamento), um mecanismo específico pode optar por otimizá-lo de maneira um pouco diferente.


1
Obrigado pela resposta. Acho que estava procurando uma maneira de usar os alertas enquanto ainda mantinha a estrutura de atribuição múltipla (a = b = c), mas não acho que isso seja possível.
David Calhoun

1
Instruções individuais como essa em javascript (e, apesar de várias expressões, que funcionam em uma única instrução) podem ser consideradas atômicas. Você teria que terminar.
Joel Coehoorn

1

Já está claro que eles não são os mesmos. A maneira de codificar isso é

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

E que tal deixar a atribuição? Exatamente o mesmo que var, não deixe a atribuição let confundir você por causa do escopo do bloco.

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

Poderíamos fazer o seguinte:

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

Nota: btw, eu não recomendo usar várias atribuições, nem mesmo várias declarações na mesma linha.


-3

coffee-script pode fazer isso com calma ..

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

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


7
Isso realmente não responde à pergunta. Por favor, leia novamente a pergunta.
Martin

30
que se preocupa com CoffeeScript
neaumusic
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.