Assegnazione multipla a sinistra con JavaScript


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

Questo equivale a questo:

var var1 = var2 = var3 = 1;

Sono abbastanza sicuro che questo sia l'ordine in cui sono definite le variabili: var3, var2, var1, che sarebbe equivalente a questo:

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

C'è un modo per confermare questo in JavaScript? Stai usando qualche profiler forse?


6
L'ASSEGNA ACCADE IL DIRITTO DI SINISTRA precedenza operatore javascript
neaumusica

è applicabile anche se lo uso this.var1 = this.var2 = this.var3 = 1?
Gangadhar JANNU,

Risposte:


404

In realtà,

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

non è equivalente a:

var var1 = var2 = var3 = 1;

La differenza sta nel scoping:

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!

In realtà questo dimostra che i compiti sono associativi giusti. L' badesempio è equivalente a:

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

44
Dang, è inaspettato. Grazie per il suggerimento, starò attento.
David Calhoun,

10
@ SkinnyG33k perché è da destra a sinistra. quindi analizzerà il più a destra prima del più a sinistra. così var var1=var2succede dopo var3 = 1e dopo var2 = var3. è comevar3=1; var2=var3; var var1=var2
gcb

12
Solo per notare: se sai che vuoi fare questo tipo di cose in anticipo, potresti ancora spezzare la definizione dall'incarico. Quindi: var v1, v2, v3;Più tardi: v1 = v2 = v3 = 6;saranno ancora nell'ambito locale. Dato che David ha menzionato gli avvisi, questo funzionerebbe come previsto (se pre-var'd):alert(v1 = v2 = v3 = 6);
ShawnFumo

3
Esattamente. Ma se seguiamo alcune buone pratiche comuni, in questo caso dichiarando le nostre variabili in alto possiamo evitare errori indesiderati ed evitare che le variabili locali perdano portata globale. Vedi: jsfiddle.net/gleezer/r9Mu8/1
Nobita

1
"Dang, è inaspettato." Perché questo sarebbe inaspettato? La maggior parte delle lingue richiede di dichiarare le variabili prima dell'uso. JavaScript non è diverso, se si trascura di dichiarare la propria variabile, l'impostazione predefinita è l'oggetto globale della finestra. Inizia a usare "Usa rigoroso" nel tuo javascript e diventerai un programmatore JavaScript migliore.
cchamberlain,

20

L'assegnazione in JavaScript funziona da destra a sinistra. var var1 = var2 = var3 = 1;.

Se il valore di una di queste variabili è 1dopo questa affermazione, logicamente deve essere iniziato da destra, altrimenti il ​​valore o var1e var2sarebbe indefinito.

Puoi considerarlo equivalente a var var1 = (var2 = (var3 = 1));dove viene valutata per prima la serie di parentesi più interna.


1
Grazie, questo sicuramente aiuta. Aiuta a pensare in termini di quali errori verrebbero generati se fosse valutato diverso da destra a sinistra (in questo caso, l'errore sarebbe che var1 / var2 non sono definiti).
David Calhoun,

5
In realtà è un errore di sintassi. Non puoi avere (subito dopo var. Rimozione del gruppo esterno di parentesi permette di compilare senza errori, var var1 = (var2 = (var3 = 1));. All'epoca pensavo che non illustrasse altrettanto bene il punto, ma suppongo che sia lo stesso.
Justin Johnson,

var var1 = var2 = var3 = 1;. uguale a var var3 = 1; var var2 = var3; var var1 = var2;
xgqfrms

8

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

In questo caso la varparola chiave è applicabile a tutte e tre le variabili.

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

che non è equivalente a questo:

var var1 = var2 = var3 = 1;

In questo caso dietro le schermate la varparola chiave è applicabile solo a var1causa di un sollevamento variabile e il resto dell'espressione viene valutato normalmente in modo che le variabili var2, var3diventino globali

Javascript tratta questo codice in questo ordine:

/*
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 si comporta come una moltiplicazione (ad es. !!a * !!b)

(a || b)è logicamente (a ? a : b)e si comporta come aggiunta (ad es. !!a + !!b)

(a = 0, b)è l'abbreviazione di non preoccuparsi se aè la verità, implicitamente ritornob


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

Precedenza operatore JavaScript (ordine delle operazioni)

Si noti che l'operatore virgola è in realtà l'operatore meno privilegiato, ma le parentesi sono le più privilegiate e vanno di pari passo quando si costruiscono espressioni di una riga.


Alla fine, potresti aver bisogno di 'thunk' piuttosto che di valori hardcoded, e per me un thunk è sia la funzione che il valore risultante (la stessa 'cosa').

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

windowInnerHeight(); // a thunk

4

Prova questo:

var var1=42;
var var2;

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

Nota il singolo '=' nel primo avviso. Questo mostrerà che il risultato di un'espressione di assegnazione è il valore assegnato e il secondo avviso ti mostrerà che si è verificata l'assegnazione.

Ne consegue logicamente che l'incarico deve essere incatenato da destra a sinistra. Tuttavia, poiché questo è tutto atomico per il javascript (non c'è threading) un determinato motore può scegliere di ottimizzarlo in modo leggermente diverso.


1
Grazie per la risposta. Penso che stavo cercando un modo per utilizzare gli avvisi pur mantenendo la struttura di assegnazione multipla (a = b = c), ma non credo sia possibile.
David Calhoun,

1
Dichiarazioni individuali come quelle in javascript (e, sebbene diverse espressioni, che tutto risolva in una singola istruzione) possono essere considerate atomiche. Dovresti romperlo.
Joel Coehoorn,

1

Ormai è chiaro che non sono gli stessi. Il modo di codificare è

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

E che dire di lasciare assigment? Esattamente come var, non lasciare che l'assegnazione lasciati confondere a causa dell'ambito del blocco.

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

Potremmo fare quanto segue:

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

Nota: a proposito, non consiglio di utilizzare più assegnazioni, nemmeno più dichiarazioni nella stessa riga.


-3

coffee-script posso farlo con aplomb ..

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

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


7
Questo non risponde davvero alla domanda. Si prega di rileggere la domanda.
Martin,

30
chi se ne frega di coffeescript
neaumusic
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.