2010-02-14 23 views
6

Estoy estudiando para un examen de JavaScript en este momento. También tengo un poco de conocimiento de C y Perl, así que estoy familiarizado con la notación de prefijo y postfijo en los tres idiomas.¿Por qué la notación postfix de JavaScript es diferente de C y Perl?

Me hicieron un examen de práctica en línea para ello y un error que hice fue evaluar el siguiente código:

var x = 10; 
x += x--; 

Ahora, pensé que iba a evaluar a 19, ya que sería 10 + 10, luego restar 1 para hacer 9. Pero la respuesta que recibí fue que estaba mal y en realidad se evalúa a 20. Pensé que sonaba un poco sospechoso, así que lo probé en un documento HTML, y salió con 20 de nuevo. Luego probé los equivalentes en C y Perl y los evalué en 19.

¿Alguien puede explicarme por qué JavaScript evalúa la respuesta como 20 cuando otros idiomas la evalúan como 19? La respuesta que obtuve de la prueba no era demasiado claro para mí:

El incremento y decremento ++ - operadores pueden colocar ya sea antes o después de un operando. Si el operador de incremento o decremento se coloca antes del operando, la operación se produce inmediatamente. Si el operador de incremento o decremento se coloca después del operando, el cambio en el valor del operando no es aparente hasta la próxima vez que se acceda al operando en el programa. Así, la expresión x + = x-- es equivalente a x = x + 10 que evalúa a 20.

+3

¡Ah, cómo odio este tipo de estúpidas preguntas de "gotcha"! Los operadores de incremento/decremento de Postfix nunca deberían aparecer en una expresión que contenga otra referencia a la variable que está (en | de) crementado. –

+6

en C, esto es un comportamiento indefinido; cualquier código que contenga este fragmento está inherentemente roto – Christoph

+0

¿'' = = no introduce un punto de secuencia? –

Respuesta

6

La ampliación de la declaración

x += x--; 

al código JS más prolija

x = x + (function(){ var tmp = x; x = x - 1; return tmp; })(); 

el resultado tiene mucho sentido, como lo hará evaluar a

x = 10 + (function(){ var tmp = 10; x = 10 - 1; return tmp; })(); 

que es 20. Tenga en cuenta que JS evalúa las expresiones de izquierda a derecha, incluidas las asignaciones compuestas, es decir, el valor de x se almacena en caché antes de ejecutar x--.


También se podría pensar de esta manera: Si se asume de izquierda a derecha orden de evaluación, JS analiza la asignación como

x := x + x-- 

mientras que Perl usará

x := x-- + x 

Pongo No veo ningún argumento convincente a favor o en contra de cualquiera de las opciones, por lo que es mala suerte que los diferentes idiomas se comporten de manera diferente.

+1

Gracias, eso lo deja bastante claro, aunque sigue siendo molesto. Supongo que está ahí como un gotcha. ¡Imagino que nadie usaría un código como este a menos que se ofusque deliberadamente! –

3

en C/C++, cada variable sólo se puede cambiar una vez en cada declaración (creo que la terminología exacta es: solo una vez entre dos puntos de código, pero no estoy seguro).

Si se escribe

x += x--; 

va a cambiar el valor de x en dos ocasiones:

  • está disminuyendo x utilizando el postfix - operador
  • se está ajustando el valor de x utilizando la asignación

Aunque puede escribir esto y el compilador no se quejará al respecto (no estoy seguro, es posible que desee comprobar los diferentes niveles de advertencia), el resultado no está definido y puede ser diferente en cada compilador.

+2

El término que está buscando es "punto de secuencia", y es significativamente diferente de "cada afirmación". – jamesdlin

+0

Sí, tienes razón James. Gracias por señalar esto. Más información sobre los puntos de secuencia en Wikipedia: http://en.wikipedia.org/wiki/Sequence_point. – Patrick

1

En C, la línea

x += x--; 

es un comportamiento indefinido. Parece que su compilador particular es tratarla como:

oldx = x--; 
x = x + oldx 

Sin embargo, la especificación ECMAScript qué especifique op= - y se obtiene el valor de la mano del lado izquierdo antes de evaluar la derecha-mano lado.

Por lo que sería equivalente a:

oldx = x--; 
x = oldx + oldx 
1

Básicamente, el valor de x se deduce después de la asignación. Este ejemplo podría hacerlo más claro (ejecute en la consola Firebug)

var x = y =10;  
x += y--;   
console.log(x , y); // outputs 20 9 
Cuestiones relacionadas