Affectation multiple à gauche avec JavaScript

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

C'est équivalent à ceci:

var var1 = var2 = var3 = 1;

Je suis assez certain que c'est l'ordre dans lequel les variables sont définies: var3, var2, var1, ce qui équivaudrait à ceci:

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

Existe-t-il un moyen de le confirmer en JavaScript? Vous utilisez éventuellement un profileur?

David Calhoun
la source
6
L'ASSIGNATION SE PASSE DE DROITE À GAUCHE
Priorité de l'
est-ce également applicable si j'utilise this.var1 = this.var2 = this.var3 = 1?
Gangadhar JANNU

Réponses:

404

Réellement,

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

n'est pas équivalent à:

var var1 = var2 = var3 = 1;

La différence réside dans la portée:

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 fait, cela montre que les affectations sont bien associatives. L' badexemple est équivalent à:

var var1 = (window.var2 = (window.var3 = 1));
Croissant frais
la source
44
Dang, c'est inattendu. Merci pour la pointe, je vais faire attention à cela.
David Calhoun
10
@ SkinnyG33k parce que c'est de droite à gauche. il analysera donc le plus à droite avant le plus à gauche. ainsi var var1=var2se produit après var3 = 1et après var2 = var3. c'est commevar3=1; var2=var3; var var1=var2
gcb
12
Juste à noter: si vous savez que vous voulez faire ce genre de chose à l'avance, vous pouvez toujours séparer la définition de la tâche. Donc: var v1, v2, v3;puis plus tard: v1 = v2 = v3 = 6;ils seront toujours dans la portée locale. Puisque David a mentionné des alertes, cela fonctionnerait comme prévu (si pré-var'd):alert(v1 = v2 = v3 = 6);
ShawnFumo
3
Exactement. Mais si nous suivons certaines bonnes pratiques courantes, dans ce cas, en déclarant nos variables en haut, nous pouvons éviter les erreurs indésirables et éviter que les variables locales ne fuient vers la portée globale. Voir: jsfiddle.net/gleezer/r9Mu8/1
Nobita
1
"Dang, c'est inattendu." Pourquoi cela serait-il inattendu? La plupart des langages vous obligent à déclarer vos variables avant utilisation. JavaScript n'est pas différent, si vous négligez de déclarer votre variable, il utilise par défaut l'objet de fenêtre global. Commencez à utiliser «use strict» dans votre javascript et vous deviendrez un meilleur programmeur JavaScript.
cchamberlain
20

L'affectation en javascript fonctionne de droite à gauche. var var1 = var2 = var3 = 1;.

Si la valeur de l'une de ces variables est 1après cette instruction, alors logiquement, elle doit avoir commencé à partir de la droite, sinon la valeur ou var1et var2ne serait pas définie.

Vous pouvez le considérer comme équivalent à l' var var1 = (var2 = (var3 = 1));endroit où l'ensemble de parenthèses le plus intérieur est évalué en premier.

Justin Johnson
la source
1
Merci, cela aide vraiment. Il est utile de penser en termes de quelles erreurs seraient générées si elle était évaluée autrement que de droite à gauche (dans ce cas, l'erreur serait que var1 / var2 ne sont pas définies).
David Calhoun
5
C'est en fait une erreur de syntaxe. Vous ne pouvez pas avoir (immédiatement après var. Retrait de l'ensemble extérieur de parenthèses permet de compiler sans erreur, var var1 = (var2 = (var3 = 1));. À l'époque, je pensais que cela n'illustrait pas aussi bien ce point, mais je suppose que c'est la même chose.
Justin Johnson
var var1 = var2 = var3 = 1;. égal à var var3 = 1; var var2 = var3; var var1 = var2;
xgqfrms
8

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

Dans ce cas, le varmot-clé est applicable aux trois variables.

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

ce qui n'est pas équivalent à ceci:

var var1 = var2 = var3 = 1;

Dans ce cas, le varmot-clé derrière les écrans n'est applicable qu'à en var1raison du levage des variables et le reste de l'expression est évalué normalement, de sorte que les variables var2, var3deviennent globales

Javascript traite ce code dans cet ordre:

/*
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
la source
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)est logiquement (a ? b : a)et se comporte comme une multiplication (par exemple.!!a * !!b )

(a || b)est logiquement (a ? a : b)et se comporte comme l'addition (par exemple.!!a + !!b )

(a = 0, b)est court pour ne pas se soucier si ac'est la vérité, retourb


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

Priorité des opérateurs JavaScript (ordre des opérations)

Notez que l'opérateur virgule est en fait l'opérateur le moins privilégié, mais que les parenthèses sont les plus privilégiées et qu'elles vont de pair lors de la construction d'expressions sur une ligne.


Finalement, vous aurez peut-être besoin de «thunks» plutôt que de valeurs codées en dur, et pour moi, un thunk est à la fois la fonction et la valeur résultante (la même «chose»).

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

windowInnerHeight(); // a thunk
neaumusic
la source
4

Essaye ça:

var var1=42;
var var2;

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

Notez le simple '=' dans la première alerte. Cela montrera que le résultat d'une expression d'affectation est la valeur assignée, et la deuxième alerte vous montrera que l'affectation s'est produite.

Il s'ensuit logiquement que l'affectation doit s'être enchaînée de droite à gauche. Cependant, comme tout cela est atomique pour le javascript (il n'y a pas de threading), un moteur particulier peut choisir de l'optimiser un peu différemment.

Joël Coehoorn
la source
1
Merci d'avoir répondu. Je pense que je cherchais un moyen d'utiliser les alertes tout en conservant la structure à affectations multiples (a = b = c), mais je ne pense pas que ce soit possible.
David Calhoun
1
Des déclarations individuelles comme celle en javascript (et, bien que plusieurs expressions, qui fonctionnent toutes en une seule instruction) peuvent être considérées comme atomiques. Vous auriez à le casser.
Joel Coehoorn
1

Il est clair maintenant qu'ils ne sont pas les mêmes. La façon de coder c'est

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

Et, qu'en est-il de l'affectation de laissez? Exactement la même chose que var, ne laissez pas l'attribution de let vous dérouter à cause de la portée du bloc.

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

Nous pourrions faire ce qui suit:

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

Remarque: btw, je ne recommande pas d'utiliser plusieurs affectations, pas même plusieurs déclarations dans la même ligne.

fenderOne
la source
-3

coffee-script peut accomplir cela avec aplomb.

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

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

Alex Gray
la source
7
Cela ne répond pas vraiment à la question. Veuillez relire la question.
Martin
30
qui se soucie de coffeescript
neaumusic