Asignación múltiple a la izquierda con JavaScript

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

Esto es equivalente a esto:

var var1 = var2 = var3 = 1;

Estoy bastante seguro de que este es el orden en que se definen las variables: var3, var2, var1, lo que sería equivalente a esto:

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

¿Hay alguna forma de confirmar esto en JavaScript? ¿Usa algún perfilador posiblemente?

David Calhoun
fuente
66
LA ASIGNACIÓN SUCEDE EL DERECHO A
DEJAR la
¿Esto también es aplicable si lo uso this.var1 = this.var2 = this.var3 = 1?
Gangadhar JANNU

Respuestas:

404

Realmente,

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

no es equivalente a:

var var1 = var2 = var3 = 1;

La diferencia está en el alcance:

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!

En realidad, esto muestra que la asignación es correcta asociativa. El badejemplo es equivalente a:

var var1 = (window.var2 = (window.var3 = 1));
Creciente Fresco
fuente
44
Dang, eso es inesperado. Gracias por el consejo, tendré cuidado con eso.
David Calhoun
10
@ SkinnyG33k porque es de derecha a izquierda. entonces analizará la derecha más que la izquierda más. Así var var1=var2sucede después var3 = 1y después var2 = var3. es comovar3=1; var2=var3; var var1=var2
gcb
12
Solo para tener en cuenta: si sabe que desea hacer este tipo de cosas con anticipación, aún puede dividir la definición de la tarea. Entonces: var v1, v2, v3;Luego, más adelante: v1 = v2 = v3 = 6;todavía estarán en el ámbito local. Desde que David mencionó las alertas, esto funcionaría como se esperaba (si se ha modificado previamente):alert(v1 = v2 = v3 = 6);
ShawnFumo
3
Exactamente. Pero si seguimos algunas de las mejores prácticas comunes, en este caso al declarar nuestras variables en la parte superior, podemos evitar errores no deseados y evitar que las variables locales se filtren al alcance global. Ver: jsfiddle.net/gleezer/r9Mu8/1
Nobita
1
"Dang, eso es inesperado". ¿Por qué sería esto inesperado? La mayoría de los idiomas requieren que declares tus variables antes del uso. JavaScript no es diferente, si descuida declarar su variable, el valor predeterminado es el objeto de ventana global. Comience a usar 'use estricto' en su javascript y se convertirá en un mejor programador de JavaScript.
cchamberlain
20

La asignación en JavaScript funciona de derecha a izquierda. var var1 = var2 = var3 = 1;.

Si el valor de cualquiera de estas variables es 1después de esta declaración, entonces lógicamente debe haber comenzado desde la derecha, si el valor o var1y var2sería indefinido.

Puede pensarlo como equivalente a var var1 = (var2 = (var3 = 1));donde se evalúa primero el conjunto de paréntesis más interno.

Justin Johnson
fuente
1
Gracias, esto definitivamente ayuda. Es útil pensar en términos de qué errores se generarían si se evaluara de otra manera que no sea de derecha a izquierda (en este caso, el error sería que var1 / var2 no están definidos).
David Calhoun
55
En realidad es un error de sintaxis. No puede tener (inmediatamente después var. Extracción del conjunto exterior de paréntesis permite que se compila sin error, var var1 = (var2 = (var3 = 1));. En ese momento sentí que no ilustraba el punto tan bien, pero supongo que es lo mismo.
Justin Johnson el
var var1 = var2 = var3 = 1;. igual a var var3 = 1; var var2 = var3; var var1 = var2;
xgqfrms
8

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

En este caso, la varpalabra clave es aplicable a las tres variables.

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

que no es equivalente a esto:

var var1 = var2 = var3 = 1;

En este caso, la varpalabra clave detrás de las pantallas solo es aplicable var1debido a la elevación variable y el resto de la expresión se evalúa normalmente para que las variables var2, var3se vuelvan globales

Javascript trata este código en este orden:

/*
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; 
Gangadhar JANNU
fuente
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)es lógicamente (a ? b : a)y se comporta como una multiplicación (p. ej. !!a * !!b)

(a || b)es lógicamente (a ? a : b)y se comporta como una suma (p. ej. !!a + !!b)

(a = 0, b)es corto para no preocuparse si aes verdad, implícitamente regresab


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

Precedencia del operador de JavaScript (orden de operaciones)

Tenga en cuenta que el operador de coma es en realidad el operador menos privilegiado, pero los paréntesis son los más privilegiados, y van de la mano al construir expresiones de una línea.


Eventualmente, es posible que necesite 'thunks' en lugar de valores codificados, y para mí, un thunk es tanto la función como el valor resultante (la misma 'cosa').

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

windowInnerHeight(); // a thunk
neaumusic
fuente
4

Prueba esto:

var var1=42;
var var2;

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

Tenga en cuenta el único '=' en la primera alerta. Esto mostrará que el resultado de una expresión de asignación es el valor asignado, y la segunda alerta le mostrará que la asignación ocurrió.

Se deduce lógicamente que la asignación debe haberse encadenado de derecha a izquierda. Sin embargo, dado que todo esto es atómico para el JavaScript (no hay subprocesos), un motor en particular puede optar por optimizarlo de manera un poco diferente.

Joel Coehoorn
fuente
1
Gracias por la respuesta. Creo que estaba buscando una forma de usar las alertas mientras mantenía la estructura de asignación múltiple (a = b = c), pero no creo que sea posible.
David Calhoun
1
Las declaraciones individuales como esa en JavaScript (y, aunque varias expresiones, que todo funciona en una sola declaración) pueden considerarse atómicas. Tendrías que romperlo.
Joel Coehoorn el
1

Ahora está claro que no son lo mismo. La forma de codificar eso es

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

Y, ¿qué pasa con dejar asignación? Exactamente lo mismo que var, no permita que la asignación let lo confunda debido al alcance del bloque.

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

Podríamos hacer lo siguiente:

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

Nota: por cierto, no recomiendo usar múltiples asignaciones, ni siquiera múltiples declaraciones en la misma línea.

guardabarros
fuente
-3

coffee-script puede lograr esto con aplomo.

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

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

Alex Gray
fuente
77
Esto realmente no responde la pregunta. Por favor, vuelva a leer la pregunta.
Martin
30
a quién le importa coffeescript
neaumusic