En JavaScript, ¿hay alguna diferencia si llamo a una función entre paréntesis?

105

Noté una diferencia al llamar a una función con paréntesis vacíos o sin ningún paréntesis. Sin embargo, no paso ningún argumento a la función, así que me pregunté cuál sería la diferencia entre:

window.onload = initAll();

y

window.onload = initAll;

Explique el principio detrás de esto.

Decano
fuente
24
@JS Bangs: solo en inglés de EE. UU.; no en otro lugar. Aunque los programadores tienden a llamarlos "paréntesis" para evitar confusiones, en inglés británico los redondeados se conocen simplemente como corchetes. Los cuadrados se conocen como "corchetes". en.wikipedia.org/wiki/Bracket
Rob Levine
13
en serio, el nombre oficial de UNICODE es paréntesis. 0028 ( PARENTESIS IZQUIERDA = paréntesis de apertura (1.0) y 0029 ) PARENTESIS DERECHA = paréntesis de cierre (1.0) - unicode.org/charts/charindex.html#P y lo que Dictionary.com tiene que decir al respecto - dictionary.reference.com/ navegar / PARENTHESIS "Una o ambas líneas curvas verticales, () ..."
8
Así que esto no es solo una cosa del "inglés de EE. UU.", Es una definición estándar internacional porque UNICODE es un estándar internacional.
2
@fuzzy - ¿De dónde sacas tus datos, en serio? {}se llaman paréntesis de ardilla.
Anurag
7
@fuzzy lollipop - Unicode es un estándar internacional para codificar caracteres como bytes, no para nombrar. Los autores del documento Unicode no afirman que el nombre de pila de un personaje sea un estándar internacional. Es el código versus el carácter que están definiendo. Sin embargo, es posible que desee señalar que también se refieren a [y] como corchetes (no solo "corchetes"), y que se refieren a todos los [, {y (como caracteres entre corchetes. Debe esforzarse por comprender los matices en la forma en que diferentes lugares usan las mismas palabras. Muy importante si eres parte de un equipo internacional.
Rob Levine

Respuestas:

161
window.onload = initAll();

Esto se ejecuta de initAll() inmediato y asigna el valor de retorno de la función a window.onload. Por lo general, esto no es lo que desea. initAll()tendría que devolver una función para que esto tenga sentido.

window.onload = initAll;

esto asigna la función real a window.onload- esto es posible porque en JavaScript, como dice @Felix, las funciones son objetos de primera clase - sin ejecutarlo. initAllserá ejecutado por el evento de carga.

Pekka
fuente
18
Es importante mencionar aquí que las funciones son objetos de primera clase en JavaScript.
Felix Kling
136

Lo que dice Pekka es correcto, pero quiero desarrollar un poco con un ejemplo que ayudará a explicarle a alguien que no comprende completamente los indicadores de función o los delegados.

No lo usaré window.onloadporque es un poco complicado de demostrar. Usaré una función de multiplicación simple para hacer una demostración en su lugar:

function Multiply(operator, operand) {
    return operator * operand;
}

Esto también podría escribirse:

Multiply = function(operator, operand) {
    return operator * operand;
}

Mientras que en el primer ejemplo, la implicación puede no ser obvia, el segundo ejemplo muestra más claramente que estamos asignando una función que tiene 2 parámetros a una variable llamada Multiply, y este concepto de funciones como asignaciones es común en JavaScript. Ésta es una pequeña demostración del hecho de que las funciones son "ciudadanos de primera clase" , es decir, pueden transmitirse exactamente como si estuviéramos transmitiendo valores.

Entonces ahora a la diferencia de asignación:

var operator = 3;
var operand = 4;
var ret = Multiply(operator, operand);

En el momento de definir la variable ret, Multiplyse ejecuta y se asigna el valor de retorno - se retvuelve igual a 12.

Intentémoslo de nuevo de una manera diferente:

var operator = 3;
var operand = 4;
var ret = Multiply;

Ahora, en el punto de definir ret, se retconvierte en tu Multiplyfunción en lugar de ser el resultado obtenido de tu Multiplyfunción. Las llamadas a ret()harán Multiplyque se ejecute su función, y puede llamarla exactamente como si hubiera llamado Multiply(operator, operand):

var out = ret(3, 4);

es lo mismo que

var out = Multiply(3, 4);

Efectivamente ha dicho que lo va a utilizar retcomo delegado Multiply(). Al llamar ret, realmente nos referimos a la Multiplyfunción.

De vuelta a tu window.onload. Piense en esto como:

window.onload = function() {
    //Doing what all good window.onload functions should do...
}

initAll = function() {
    return 12;
}

Entonces, como puede ver, window.onloades una función como cualquier otra función, no tiene nada de especial. Puede asignarle un valor, asignarle una función, anularlo si lo desea; el punto es que no hay nada más especial window.onloadque su propia función. Lo único ligeramente diferente es que la ventana lo llama cuando se carga. [Descargo de responsabilidad: nunca he anulado las funciones de la ventana, por lo que no estoy seguro de si esto causará repercusiones negativas. Uno esperaría que verifiquen si una función está asignada antes de llamarla, es decir if (window.onload) window.onload();].

Ahora llamar initAll()lo que estamos diciendo es:

window.onload = initAll();

que bien podría decir:

window.onload = 12;

Pero cuando decimos initAllsin los paréntesis, lo que realmente estamos diciendo es: quiero reemplazar lo que sea mi función window.onload, con una nueva función, es decir, quiero reemplazarla con mi initAllfunción, de modo que cualquier llamada a window.onloadejecute mi initAllcódigo.

Entonces:

window.onload = function() {
    //Doing what all good window.onload functions should do...
}

se reemplaza con:

window.onload = function() {
    return 12;
}

Entonces, cualquier llamada a window.onloadejecutará su initAllfunción en lugar de lo que window.onloadfue originalmente. Ha reemplazado la función original con su nueva función.

De hecho, también podrías escribir:

window.onload = function() {
    //Write all your init code right in here instead of having a separate 
    //initAll function.
}

Otro ejemplo que puede demostrar mejor es este:

var d = new Date();
var currentTime = d.getTime();

Cualquiera que sea la hora a la que dse define, termina asignada currentTime. Genial, pero eso solo es útil si queremos saber a qué hora se llamó a la función que contiene ese código, es decir, en el momento de carga de la página. ¿Qué pasa si queremos la hora actual en cualquier momento que currentTimese llame?

var currentTime = function() {
    var d = new Date();
    return d.getTime();
}

var a = currentTime(); //The current time at the point a is defined...
var b = currentTime;   //b is a functional reference to currentTime...
var c = b(); //The current time when variable c is defined
var d = c; //The current time when variable c was defined

¿Observa cómo llamamos b()a nuestras asignaciones cy dexactamente como podríamos llamar currentTime()?

BenAlabaster
fuente
¡Maravillosa respuesta!
Shadi Almosri
Oye, ¿qué pasa si quiero agregar una función que toma argumentos en un detector de eventos?
Shemiroth
16

Las funciones en javascript son ciudadanos de primera clase y, como tales, pueden asignarse a otras variables o pasarse como argumentos.

Entonces, cuando lo hagas

window.onload = initAll;

Está configurando la onloadpropiedad del windowobjeto para hacer referencia a la initAllfunción en sí.

Cuando tu lo hagas

window.onload = initAll();

Está configurando la onloadpropiedad para que mantenga el valor de retorno de initAll, ya que se ejecutará en su lugar en esa línea.

Peter Bailey
fuente
10

initAll es una referencia a un valor de función y el operador de corchetes adjunto al nombre de la función EJECUTA este objeto de función.

Entonces, si haces algo como

a = initAll

luego aserá lo mismo que initAll, por ejemplo, puede hacerlo a(), pero con

a = initAll()

la variable aobtendrá el valor de retorno de la initAllfunción ejecutada

Andris
fuente
8

Llego 6 años tarde, pero creo que esto podría haberse explicado de manera mucho más simple que las respuestas anteriores.

Entonces aquí está el TLDR ; o vista de pájaro al llamar a funciones usando y no usando ()'s

Tomemos esta función por ejemplo:

function foo(){
return 123;
}

si registra "foo" - sin ()

console.log(foo); 

---outout------
function foo(){
return 123;
}

No usar ()medios para buscar la función en sí . Haría esto si desea que se transmita como una devolución de llamada.


si registra "foo ()" - con ()

console.log(foo());
-----output-----
 123

Usar ()después de una función significa ejecutar la función y devolver su valor .

garrettmac
fuente