without objects es6 array javascript object variable-assignment

objects - Truco de código JavaScript: ¿Cuál es el valor de foo.x



object.assign array (6)

Como entiendo expresión:

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

exactamente igual que:

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

Y después de esto se hizo obvio que:

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

Encontré este problema en una colección de preguntas de la entrevista frontal de GitHub:

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

Pregunta: ¿Cuál es el valor de foo.x?

La respuesta es undefined .

He investigado un poco y entiendo que este problema es (corrígeme si me equivoco):

  • var foo = {n: 1}; declara un objeto foo que tiene una propiedad n igual a 1.
  • var bar = foo; declara una bar objetos que se refiere al mismo objeto que foo .
  • foo.x = foo = {n: 2}; que creo es igual a foo.x = (foo = {n: 2});
  • Y luego obtuve foo.x es igual a undefined . Sin embargo, el valor de bar.x es el objeto {n:2} .

Si bar y foo refieren al mismo objeto, ¿por qué bar.x obtuvo un valor mientras que foo.x undefined está undefined ? Lo que realmente está sucediendo en foo.x = foo = {n: 2}; ?


Creo que en Javascript no puede asignar un valor a una propiedad que no existe si el objeto no está vacío. por lo tanto, en este caso, el objeto foo tiene un par de propiedades y valores que es {n: 1} así que dado que no está vacío y no tiene la propiedad ax, no puede asignar, pero dado que asigna al objeto de barra un valor que es el objeto foo , tendrá el valor sea cual sea el foo


Es una cuestión de entender que las variables de objeto son meras referencias a los objetos en JavaScript y no los objetos en sí.

var foo = {n: 1} -> foo se refiere al objeto real {n: 1} var bar = foo -> bar ahora también es una referencia al objeto real {n: 1}

La parte difícil es, por supuesto, la tercera línea: foo.x = foo = {n: 2}

Esto es equivalente a: (reference to {n: 1}).x = (foo = {n: 2}) -> después de evaluar completamente esta línea, foo se convierte en una referencia al nuevo objeto {n: 2}; sin embargo, dado que foo se refiere al objeto original {n: 1} antes de la evaluación de la línea, el objeto original {n: 1} convierte en {n: 1, x: [reference to]{n: 2}} después del se evalúa la línea y se podrá acceder al objeto modificado a través de la bar referencia. Si no hubiera una barra de referencia, el objeto original sería destruido


Pensé agregar otra, lo que encontré, una forma útil de pensar sobre esto.

Esas últimas asignaciones de variables son equivalentes a escribir bar.x = foo = {n:2}; , porque esas variables son solo referencias a lo mismo en la memoria.

En otras palabras, foo y bar son, al principio, ambos haciendo referencia al mismo objeto, {n:1} . Cuando utiliza foo.x = , accede a {n:1} y le agrega la propiedad x . ¡Esto podría hacerse con bar o foo porque ambos apuntan al mismo objeto en la memoria! No hace ninguna diferencia.

Luego, cuando complete esa línea, foo.x = foo = {n:2} , está creando otro objeto nuevo en la memoria mediante la sintaxis literal del objeto y configurando foo para que apunte a ese objeto, {n:2} , en su lugar de lo que ahora es {n:1, x: {n: 2} . Sin embargo, esto no afecta a lo que señaló foo cuando le agregaste la propiedad x .

Esto es bastante confuso, pero creo que tiene sentido que pienses en el hecho de que las variables son solo punteros a lugares / objetos en la memoria, y que la sintaxis literal del objeto no está cambiando el objeto previamente existente (aunque se vean similares). Está creando uno nuevo.

El comienzo de la respuesta aceptada a esta pregunta también puede ser útil.


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

Aquí foo se refiere al objeto {n: 1} antes de la asignación, es decir, antes de que se ejecute la declaración.

La declaración puede reescribirse como foo.x = (foo = {n: 2});

En términos de objeto, la declaración anterior puede reescribirse como {n: 1} .x = ({n: 1} = {n: 2});

Dado que la asignación ocurre de derecha a izquierda solamente. Entonces, aquí solo tenemos que verificar que foo se esté refiriendo a qué objeto antes de que comience la ejecución.

Al resolver el RHS: foo = {n: 2} ; Ahora foo se refiere a {n: 2} ;

Volviendo al problema que nos queda:

foo.x = foo;

Ahora, foo.x en LHS sigue siendo {n: 1} .x, mientras que foo en RHS es {n: 2} .

Entonces, después de que se ejecute esta declaración, {n: 1} se convertirá en {n: 1, x: {n: 2}} con la barra todavía refiriéndose a ella. Donde como foo ahora se referirá a {n: 2} .

Entonces, en la ejecución, foo.x da indefinido ya que solo hay 1 valor en foo que es {n: 2}.

Pero si intenta ejecutar bar.x, obtendrá {n: 2}. O si solo ejecutas la barra, el resultado será

Objeto {n: 1, x: Objeto}


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

determina que foo.x refiere a una propiedad x del objeto {n: 1} , asigna {n: 2} a foo y asigna el nuevo valor de foo - {n: 2} - a la propiedad x de {n: 1} objeto.

Lo importante es que el foo que se refiere foo.x se determina antes de que foo cambie.

Consulte la sección 11.13.1 de la especificación ES5 :

  1. Deje que lref sea ​​el resultado de evaluar LeftHandSideExpression .

  2. Deje que rref sea ​​el resultado de evaluar AssignmentExpression .

El operador de asignación se asocia de derecha a izquierda, por lo que obtiene:

foo.x = (foo = {n: 2})

El lado izquierdo se evalúa antes que el lado derecho.