2011-12-23 10 views
13

En muchos navegadores que he probado, los bloques de JavaScript realmente devuelven un valor. Puede probarlo en cualquier consola:Utilizando el valor de retorno de un bloque en JavaScript

for(var i = 0; i < 10; i++) { 
    var sqrt = Math.sqrt(i); 
    if(Math.floor(sqrt) === sqrt) { 
     i; 
    } 
} 

El valor de "retorno" es el último número cuadrado, es decir, 9! Pero como no es una expresión, supongo, no puede hacer esto:

for(var i = 0; i < 10; i++) { 
    ... 
} + 5 

Eso no funciona. Da + 5, o 5, por supuesto, porque es una declaración separada. Poner el bucle entre paréntesis obviamente falla, y si un bloque está entre paréntesis (por ejemplo, ({f(); r}) - no funciona) se trata como un objeto y arroja un error de sintaxis.

Una forma de aprovechar el valor de retorno, como tal, es el uso de eval:

eval('for(var i = 0; i < 10; i++) {var sqrt = Math.sqrt(i);if(Math.floor(sqrt) === sqrt) {i;}}') + 5; // 14 

Pero obviamente no voy a querer utilizar eval que si es la única solución. ¿Hay alguna manera de usar el valor resultante de un bloque sin usar eval que me falta? Me gusta mucho esta característica :)

+4

Los bloques son declaraciones, no expresiones. Por lo tanto, no puede usarlos como operandos (no puede usar operadores en ellos) ... –

+0

@ ŠimeVidas: Exactamente, ¿hay alguna forma de hacer que funcionen? ¿No usas 'eval'? – Ryan

+1

Debe tratar el valor de retorno de 'eval' como la anomalía, no la restricción que JS" normalmente "(léase: ignorar afuera' eval') impone. Los bloques son ** no ** expresiones. – delnan

Respuesta

14

En JavaScript, las declaraciones devuelven valores del tipo de finalización (que no es un tipo de idioma, sino un tipo de especificación).

El tipo de finalización se utiliza para explicar el comportamiento de los estados (break, continue, return y throw) que realizan las transferencias no locales de control. Valores del tipo de finalización son triples de la forma (tipo, valor, objetivo), donde tipo es uno de normal de, descanso, siguen, retorno, o tiro, valor es cualquier valor o del lenguaje ECMAScript vacío, y objetivo es cualquier identificador ECMAScript o vacío.

Fuente: http://es5.github.com/x8.html#x8.9

Así, eval() evalúa el programa que se ha transmitido en forma de texto fuente. Ese programa (como cualquier programa de JavaScript) devuelve un valor de finalización. El segundo elemento en este valor de Finalización (el elemento "valor") se devuelve mediante la invocación eval().

Por lo tanto, con eval puede recuperar el valor de finalización de un programa de JavaScript. No conozco ningún otro método para lograr esto ...

+0

Apuesto a que este tipo de material de finalización está allí solo para especificar alguna implementación original de 'eval'. – hugomg

+1

@missingno Puedo asegurarle que el tipo de finalización es una parte esencial del idioma. El intérprete utiliza los valores de finalización para determinar el siguiente paso en la ejecución (es decir, transferir el control a la función de llamada, saltar al principio de la instrucción de iteración, etc.). –

+1

Lo siento, por la confusión. No puedo pensar en ningún otro caso, luego evaluar que se preocupe por el valor * de finalización *. (El segundo valor en ese triple, y el que importa para esta pregunta en particular) – hugomg

2

Hay una propuesta para que ES7 introduzca un do expression que permita convertir cualquier bloque en una expresión. Una expresión do evalúa un bloque y devuelve su valor de finalización.

El uso de esta sintaxis, que puede probar hoy con Babel utilizando los syntax-do-expression y transform-do-expression plugins, su ejemplo podría tener este aspecto:

function lastSquareNumber(val) { 
    return do { for(var i = 0; i < val; i++) { 
     var sqrt = Math.sqrt(i); 
     if(Math.floor(sqrt) === sqrt) { 
      i; 
     } 
    }} 
} 

console.log(lastSquareNumber(10)); 
+0

¡Genial! De alguna manera dudo que lo logre, pero también es bueno ver todo lo mismo. – Ryan

+0

Esto se ve muy bien, espero que esto se implemente en ES7 aunque tendremos que esperar por eso mientras supongo :) – SidOfc

Cuestiones relacionadas