2016-01-21 8 views
25

Questo codice:Perché il valore di foo.x non è definito in foo.x = foo = {n: 2}?

var foo = {n: 1}; 
var bar = foo; 
foo.x = foo = {n: 2}; 

Si può spiegare cosa si intende per:

foo.x = foo = {n: 2}; 

vedo che {n:2} viene assegnato foo. Perché lo undefined è assegnato a foo.x? foo = {n: 2}; restituisce undefined?

+3

Perché il downvote? Questa è una domanda interessante. – Ben

+0

@Juhana ti dispiacerebbe correggere la tua modifica? – djechlin

+0

@djechlin Cosa c'è di sbagliato in questo? – JJJ

risposta

7

Poiché la proprietà di accesso foo.x a sinistra viene valutata prima del lato destro.

Facciamo in modo più chiaro che cosa fa effettivamente il codice, dando nuovi nomi alle espressioni temporanee in corso di valutazione:

var foo0 = {n: 1}; 
var foo1 = {n: 2}; 
foo0.x = foo1; 
foo0 = foo1; 
console.log(foo0.x); 

Quindi foo0.x è foo1.x è undefined.

Nel codice originale, è possibile vedere che bar.x è {n: 2}, confermando questa spiegazione.

+0

Ora vedo che questo è corretto ma non mi sorprende che confonda le persone. – djechlin

1

Poiché si è assegnato nuovamente a un oggetto con una singola proprietà, { n: 2 }.

In JavaScript, le espressioni vengono valutate da destra a sinistra. Quindi, quando si tenta di accedere a foo.x, si sta tentando di ottenere il valore di x dal nuovo valore assegnato di foo, { n: 2 }, che è undefined.

+0

Quindi cosa fa "foo.x =" ... fare? – djechlin

+0

@djechlin viene assegnato a foo, ma poi foo viene sostituito da un oggetto senza un valore x –

4

Secondo le specifiche JavaScript, lato sinistro viene sempre valutata prima:

12.14.4 Runtime Semantica: Valutazione

AssignmentExpression [In, Resa]: LeftHandSideExpression [? Rendimento] = AssignmentExpression [? In,? Rendimento]

Se LeftHandSideExpression è né un ObjectLiteralArrayLiteral, quindi
1. Let Lref essere il risultato della valutazione LeftHandSideExpression.

http://www.ecma-international.org/ecma-262/6.0/index.html#sec-assignment-operators-runtime-semantics-evaluation

Si vede chiaramente se si aggiunge un altro riferimento all'oggetto foo:

var ref = {n:1}; 
var foo = ref; 
var bar = foo; 
foo.x = foo = {n: 2}; 

ref.x esiste perché foo.x riferisce al valore non modificata foo.

23

According to the spec, il lato sinistro di un'espressione di assegnazione viene valutato per primo, anche se l'operatore ha precedenza da destra a sinistra. Così l'espressione foo.x = foo = {n: 2} che è la stessa come foo.x = (foo = {n: 2}) è valutato in questo:

  1. valutare l'espressione di sinistra foo.x per ottenere un riferimento, che è dove il valore dell'espressione destra verrà assegnato.

  2. Valutare l'espressione della mano destra, per ottenere il valore che verrà assegnato. Il lato destro è un'altra espressione di assegnazione, in modo che viene valutata allo stesso modo:

    1. Valutare foo per determinare dove assegnare.
    2. Valutare l'espressione {n:2}, che crea un oggetto, per determinare il valore da assegnare.
    3. Assegnare {n:2} a foo e restituire {n:2}.

  3. Assegnare il valore che l'espressione a destra valutata a ({n:2}), al riferimento che foo.x risolto nel passaggio 1 (primafoo è stato assegnato un nuovo valore). Che è lo stesso di bar.x, a causa dell'attribuzione bar = foo sulla riga precedente.

Quando questo è fatto, l'oggetto originale, che bar è ancora un riferimento a, avrà una proprietà x che fa riferimento il secondo oggetto creato. foo è anche un riferimento a tale secondo oggetto, quindi foo === bar.x.

+0

Sembra che abbiamo un vincitore. – Ben

+0

come fa 'foo.x = (foo = {n: 2}) 'ha senso, non dovrebbe essere l'opposto, l'ho appena testato anche in chrome e ha gli stessi risultati –

+1

@ johnny5 Non farebbe Senta se 'pippo' non era già un oggetto, ma lo è, dalla prima affermazione. – Paulpro

Problemi correlati