2008-08-08 6 views
18

Hay dos estilos de cierre populares en javascript. El primero que llamo constructor anónimo:¿Cuál es la diferencia en el estilo de cierre

new function() { 
    var code... 
} 

y la función ejecutada en línea:

(function() { 
    var code... 
})(); 

hay diferencias de comportamiento entre los dos? ¿Hay uno "mejor" que el otro?

Respuesta

7

Ambos casos se ejecute la función, la única diferencia real es lo que puede ser el valor de retorno de la expresión, y cuál es el valor de "esto" dentro de la función.

Básicamente comportamiento de

new expression 

es efectivamente equivalente a

var tempObject = {}; 
var result = expression.call(tempObject); 
if (result is not an object) 
    result = tempObject; 

Aunque por supuesto tempObject y el resultado son valores transitorios nunca se puede ver (son detalles de implementación en el intérprete), y no hay un mecanismo JS para hacer la verificación de "no es un objeto".

Hablando en términos generales, el método "new function() {..}" será más lento debido a la necesidad de crear este objeto para el constructor.

Dicho esto, esta no debería ser una verdadera diferencia ya que la asignación de objetos no es lenta, y no debería usar dicho código en código caliente (debido al costo de crear el objeto de función y el cierre asociado).

Edición: una cosa que me di cuenta de que me perdí de esto es que el tempObject obtendrá el prototipo expression, por ejemplo. (Antes de la expression.call) tempObject.__proto__ = expression.prototype

0

El segundo ejemplo ejecutará la función después de crearla.

editar: esto no es realmente cierto.

5

@Lance: el primero también se está ejecutando. Compararlo con un constructor llamado:

function Blah() { 
    alert('blah'); 
} 
new Bla(); 

este es en realidad también está ejecutando código. Lo mismo ocurre con el constructor anónimo ...

Pero eso no era la cuestión ;-)

0

Bueno, hice una página como esta:

<html> 
<body> 
<script type="text/javascript"> 
var a = new function() { 
    alert("method 1"); 

    return "test"; 
}; 

var b = (function() { 
    alert("method 2"); 

    return "test"; 
})(); 

alert(a); //a is a function 
alert(b); //b is a string containing "test" 

</script> 
</body> 
</html> 

Sorprendentemente (para mí de todos modos) alertó tanto "método 1" y el método 2" no esperaba. "método 1" para ser alertado. La diferencia era cuáles eran los valores de ayb. a era la función en sí, mientras que b era la cadena que devolvía la función.

-4

Sí, hay diferencias entre los dos.

Ambas son funciones anónimas a y ejecutar de la misma manera. Pero, la diferencia entre los dos es que en el segundo caso, el alcance de las variables se restringe a la función anónima en sí misma.No hay posibilidad de agregar variables accidentalmente al alcance global.

Esto implica que al usar el segundo método, no está saturando el alcance de las variables globales, que es bueno ya que estos valores variables globales pueden interferir con otras variables globales que puede usar en otras bibliotecas o que se utilizan en una biblioteca de terceros.

Ejemplo:

<html> 
<body> 
<script type="text/javascript"> 

new function() { 
a = "Hello"; 
alert(a + " Inside Function"); 
}; 

alert(a + " Outside Function"); 

(function() { 
var b = "World"; 
alert(b + " Inside Function"); 
})(); 

alert(b + " Outside Function"); 
</script> 
</body> 
</html> 

En el código anterior, la salida es algo así como:

Hola Dentro Función
Hola Fuera Función
Mundial interior Función

.. Entonces, aparece un error ya que 'b' no está definido ide la función!

Por lo tanto, creo que el segundo método es mejor ... ¡más seguro!

+1

-1 Esto se debe a omitir "var" antes de "a", lo que lo hace global y no está relacionado con la pregunta. – Tomas

3

Ambos crean un cierre al ejecutar el bloque de código. Como una cuestión de estilo, prefiero el segundo por un par de razones:

No es inmediatamente obvio echando un vistazo a la primera que el código realmente se ejecutará; la línea parece es creando una nueva función, en lugar de ejecutarlo como un constructor, pero eso no es lo que realmente está sucediendo. ¡Evite el código que no hace lo que parece que está haciendo!

También (function(){ ... })(); hacen buenos tokens sujetalibros para que pueda ver inmediatamente que está entrando y saliendo de un alcance de cierre. Esto es bueno porque alerta al programador que lo lea sobre el cambio de alcance, y es especialmente útil si está haciendo un posprocesado del archivo, por ejemplo, para la minificación.

Cuestiones relacionadas