2009-06-18 12 views
410

¿Cuál es la diferencia entre las siguientes líneas de código?¿Cuál es la diferencia entre una expresión de función vs declaración en JavaScript?

//Function declaration 
function foo() { return 5; } 

//Anonymous function expression 
var foo = function() { return 5; } 

//Named function expression 
var foo = function foo() { return 5; } 
  • ¿Qué es una expresión de función llamado/anónima?
  • ¿Qué es una función declarada?
  • ¿Cómo lidian los navegadores con estos constructos de forma diferente?

¿Qué hacen las respuestas a una pregunta similar (var functionName = function() {} vs function functionName() {}) no exactamente?

+0

Aquí hay [un buen artículo sobre expresiones de funciones nombradas] (http://kangax.github.com/nfe). Las expresiones de función frente a las declaraciones se abordan en la primera sección. –

+0

La principal diferencia que IMO está levantando. Aquí hay un buen artículo sobre el tema: http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html –

Respuesta

10

La primera instrucción depende del contexto en el que se declara.

Si se declara en el contexto global, creará una variable global implícita llamada "foo" que será una variable que apunta a la función. Por lo tanto, la llamada a la función "foo()" se puede realizar en cualquier parte de su programa javascript.

Si se crea la función de un cierre que va a crear una variable local implícita llamado "foo" que luego se puede utilizar para invocar la función en el interior del cierre con "foo()"

EDIT:

Debería haber dicho también que las instrucciones de función (La primera) se analizan antes de las expresiones de función (Las otras 2). Esto significa que si declaras la función en la parte inferior de tu script, podrás utilizarla en la parte superior. Las expresiones de función solo se evalúan cuando son afectadas por el código de ejecución.

FIN EDITAR

declaraciones 2 & 3 son más o menos equivalentes entre sí. De nuevo, si se usan en el contexto global, crearán variables globales y, si se usan dentro de un cierre, crearán variables locales. Sin embargo, vale la pena señalar que el enunciado 3 ignorará el nombre de la función, por lo que esencialmente podría llamar a la función cualquier cosa. Por lo tanto

var foo = function foo() { return 5; } 

es la misma que

var foo = function fooYou() { return 5; } 
+19

'fooYou' no se ignora. Es visible en el cuerpo de la función, por lo que la función puede referirse a sí misma (por ejemplo, para implementar la recursión). –

+1

Ese es un buen punto. No pensé en eso :) – Alex

+7

Además, las expresiones de funciones nombradas son útiles para la depuración: 'var foo = function fooYou() {return 5; }; console.log (foo); console.log (foo.name); 'imprimirá' fooYou()/fooYou' (Firefox), '[Función: fooYou]/fooYou' (node.js),' función fooYou() {return 5; }/fooYou' (Chrome) o algo solo estas líneas, dependiendo de dónde lo ejecutes. – Gilead

335

En realidad, son muy similares. Cómo los llama es exactamente lo mismo. La diferencia radica en cómo el navegador los carga en el contexto de ejecución.

Las declaraciones de funciones se cargan antes de ejecutar cualquier código.

Las expresiones de función solo se cargan cuando el intérprete llega a esa línea de código.

Así que si intentas llamar a una expresión de función antes de que se cargue, ¡obtendrás un error! Si llama a una declaración de función en su lugar, siempre funcionará, porque no se puede llamar a ningún código hasta que se carguen todas las declaraciones.

Ejemplo: Expresión Función

alert(foo()); // ERROR! foo wasn't loaded yet 
var foo = function() { return 5; } 

Ejemplo: Declaración de función

alert(foo()); // Alerts 5. Declarations are loaded before any code can run. 
function foo() { return 5; } 


En cuanto a la segunda parte de su pregunta:

var foo = function foo() { return 5; } es realmente el sam e como los otros dos. Es solo que esta línea de código solía causar un error en safari, aunque ya no lo hace.

+23

La última no es lo mismo que '' var foo = function() {return 5; } ''. Porque aquí, '' foo.name'' es '' '' '', en el último, es '' 'foo'''. – JCM

+2

@JCM AFAIK, la propiedad de nombre no es parte de ECMAScript y solo se implementa en algunos navegadores. ['Function.name' en MDN] (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/name) –

+7

@ZachL Solo como ejemplo, lo que quería decir es que la segunda función tiene un nombre, donde la primera no. – JCM

1

Aunque la diferencia completa es más complicada, la única diferencia que me preocupa es cuando la máquina crea el objeto de función. Que en el caso de las declaraciones es antes de que se ejecute cualquier declaración pero después de invocar un cuerpo de cuerpo (ya sea el cuerpo del código global o una subfunción), y en el caso de las expresiones es cuando se ejecuta la declaración en la que se encuentra. Aparte de eso, para todos los intentos y propósitos, los navegadores los tratan de la misma manera.

Para ayudarlo a comprender, eche un vistazo a este rendimiento test que eliminó una suposición que yo había hecho de funciones declaradas internamente que no necesitaban ser recreadas por la máquina cuando se invoca la función externa. También es una lástima ya que me gusta escribir código de esa manera.

79

Declaración de función

function foo() { ... } 

Debido a la función de elevación , la función declarada de esta manera se puede llamar tanto después como antes de la definición.

expresión de función

  1. función llamada Expresión

    var foo = function bar() { ... } 
    
  2. Anónimo Función Expresión

    var foo = function() { ... } 
    

foo() puede llamarse solo después de la creación.

Immediately-Invoked Function Expression (IIFE)

(function() { ... }()); 

Conclusión

Crockford recomienda utilizar expresión de función, ya que deja claro que foo es una variable que contiene un valor de la función. Bueno, personalmente, prefiero usar la Declaración a menos que haya una razón para la Expresión.

+9

¡Bienvenido a Stack Overflow! ¡Gracias por publicar tu respuesta! Asegúrese de leer detenidamente [Preguntas frecuentes sobre autopromoción] (http://stackoverflow.com/faq#promotion). También tenga en cuenta que * se requiere * que publique un descargo de responsabilidad cada vez que se vincula a su propio sitio/producto. –

+1

punto de interés: js distingue entre mayúsculas y minúsculas. Sus ejemplos bloqueados no funcionan ;-) –

+1

también, usted * puede * tener un nombre IIFE: '(función myFunc() {...}());' –

17

En cuanto a tercera definición:

var foo = function foo() { return 5; } 

Aquí está un ejemplo que muestra cómo utilizar la posibilidad de llamada recursiva:

a = function b(i) { 
    if (i>10) { 
    return i; 
    } 
    else { 
    return b(++i); 
    } 
} 

console.log(a(5)); // outputs 11 
console.log(a(10)); // outputs 11 
console.log(a(11)); // outputs 11 
console.log(a(15)); // outputs 15 

Editar: ejemplo más interesante con cierres:

a = function(c) { 
return function b(i){ 
    if (i>c) { 
    return i; 
    } 
    return b(++i); 
} 
} 
d = a(5); 
console.log(d(3)); // outputs 6 
console.log(d(8)); // outputs 8 
+7

No necesita declarar la función con un nombre diferente para hacer es recursivo De hecho, diría que eso confunde las cosas. 'a = function a (i)' y al hacer 'return a (++ i)' produce el mismo resultado – PhilT

+0

Pero usar un nombre diferente para la función que la variable ilustra el punto más claramente. Felicitaciones por proporcionar un ejemplo para el uso de expresiones de funciones nombradas. – gfullam

Cuestiones relacionadas