Em JavaScript, faz diferença se eu chamar uma função com parênteses?

105

Percebi uma diferença ao chamar uma função com parênteses vazios ou sem nenhum parêntese. No entanto, não estou passando nenhum argumento para a função, então me perguntei, qual seria a diferença entre:

window.onload = initAll();

e

window.onload = initAll;

Explique o princípio por trás disso.

reitor
fonte
24
@JS Bangs - somente em inglês dos EUA; não em outro lugar. Embora os programadores tendam a chamá-los de "parênteses" para evitar confusão, no inglês do Reino Unido os arredondados são conhecidos simplesmente como colchetes. Os quadrados são conhecidos como "colchetes". en.wikipedia.org/wiki/Bracket
Rob Levine
13
falando sério, o nome oficial do UNICODE é Parêntese. 0028 ( PARÊNTESE ESQUERDO = parêntese de abertura (1.0) e 0029 ) PARÊNTESE DIREITO = parêntese de fechamento (1.0) - unicode.org/charts/charindex.html#P e o que Dictionary.com tem a dizer sobre isso - dictionary.reference.com/ browse / PARENTHESIS "Uma ou ambas as linhas curvas verticais, () ..."
8
Portanto, isso não é apenas uma coisa de "inglês dos EUA", é uma definição de padrão internacional porque UNICODE é um padrão internacional.
2
@fuzzy - De onde você tira seus fatos, sério? {}são chamados de colchetes de esquilo.
Anurag
7
@fuzzy lollipop - Unicode é um padrão internacional de codificação de caracteres como bytes, não de nomenclatura. Os autores do documento Unicode não afirmam que o nome dado para um personagem é um padrão internacional. É o código versus o personagem que eles estão definindo. No entanto, você pode notar que eles também se referem a [e] como colchetes - (não apenas "colchetes") e que se referem a todos os [, {e (como caracteres de colchetes. Você deve se esforçar para compreender as nuances na forma como diferentes lugares usam as mesmas palavras. Muito importante se você faz parte de uma equipe internacional.
Rob Levine

Respostas:

161
window.onload = initAll();

Isso é executado initAll() imediatamente e atribui o valor de retorno da função a window.onload. Geralmente não é isso que você deseja. initAll()teria que retornar uma função para que isso fizesse sentido.

window.onload = initAll;

isso atribui a função real a window.onload- isso é possível porque em JavaScript, como diz @Felix, funções são objetos de primeira classe - sem executá-lo. initAllserá executado pelo evento de carregamento.

Pekka
fonte
18
É importante mencionar aqui que as funções são objetos de primeira classe em JavaScript.
Felix Kling
136

O que Pekka disse está correto, mas eu quero elaborar um pouco com um exemplo que ajudará a explicar para alguém que não entende totalmente os ponteiros de função ou delegados.

Não vou usar window.onloadporque é um pouco artificial para demonstrar. Usarei uma função simples de multiplicação para demonstrar:

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

Isso também poderia ser escrito:

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

Enquanto no primeiro exemplo a implicação pode não ser óbvia, o segundo exemplo mostra mais claramente que estamos atribuindo uma função que tem 2 parâmetros para uma variável chamada Multiply, e este conceito de funções como atribuições é comum em todo o JavaScript. Esta é uma pequena demonstração do fato de que as funções são "cidadãos de primeira classe" , ou seja, podem ser repassadas exatamente como se estivéssemos passando valores.

Agora, para a diferença de atribuição:

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

No ponto de definição da variável ret, Multiplyé executado e o valor de retorno é atribuído - rettorna - se igual a 12.

Vamos tentar novamente de uma maneira diferente:

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

Agora, no ponto de definição ret, rettorna-se sua Multiplyfunção em oposição a ser o resultado obtido de sua Multiplyfunção. Chamadas para ret()farão com que sua Multiplyfunção seja executada, e você pode chamá-la exatamente como se tivesse chamado Multiply(operator, operand):

var out = ret(3, 4);

é o mesmo que

var out = Multiply(3, 4);

Você disse efetivamente que vai usar retcomo delegado para Multiply(). Ao chamar ret, estamos realmente nos referindo à Multiplyfunção.

De volta ao seu window.onload. Pense nisso como:

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

initAll = function() {
    return 12;
}

Como você pode ver, window.onloadé uma função como qualquer outra função, não há nada de especial nela. Você pode atribuir a ele um valor, atribuir uma função e anular se desejar - o ponto é que não há nada mais especial do window.onloadque sua própria função. A única coisa ligeiramente diferente é que ele é chamado pela janela quando é carregado. [Aviso de isenção: eu nunca realmente anulei as funções da janela, então não tenho certeza se isso causará repercussões negativas. Espera-se que eles verifiquem se uma função está atribuída antes de chamá-la, ie if (window.onload) window.onload();].

Agora chamar initAll()o que estamos dizendo é:

window.onload = initAll();

que poderia muito bem dizer:

window.onload = 12;

Mas quando dizemos initAllsem os parênteses, o que estamos realmente dizendo é: eu quero substituir qualquer que seja a minha função window.onload, por uma nova função - ou seja, eu quero substituí-la pela minha initAllfunção, para que qualquer chamada a window.onloadexecute meu initAllcódigo.

Assim:

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

é substituído por:

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

Portanto, qualquer chamada para window.onloadexecutará sua initAllfunção em vez do que window.onloadera originalmente. Você substituiu a função original pela nova função.

Na verdade, você também pode escrever:

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

Outro exemplo que pode demonstrar melhor é este:

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

Qualquer que seja a hora na hora ddefinida, ela acaba sendo atribuída currentTime. Ótimo, mas isso só é útil se quisermos saber a que horas a função que contém esse código foi chamada - ou seja, na hora de carregar a página. E se quisermos a hora atual a qualquer hora que currentTimefor chamada?

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

Observe como chamamos b()nossas atribuições ce dexatamente como poderíamos chamar currentTime()?

BenAlabaster
fonte
Resposta maravilhosa!
Shadi Almosri
Ei, e se eu quiser adicionar uma função que recebe argumentos em um ouvinte de evento?
Shemiroth
16

As funções em javascript são cidadãos de primeira classe e, como tal, podem ser atribuídas a outras variáveis ​​ou passadas como argumentos.

Então, quando você faz

window.onload = initAll;

Você está definindo a onloadpropriedade do windowobjeto para fazer referência à initAllprópria função.

Quando você faz

window.onload = initAll();

Você está definindo a onloadpropriedade para conter o valor de retorno de initAll, uma vez que ele será executado no lugar nessa linha.

Peter Bailey
fonte
10

initAll é uma referência a um valor de função e o operador colchetes anexado ao nome da função RUNS este objeto de função.

Então, se você fizer algo como

a = initAll

então ase tornará o mesmo initAll- por exemplo, você pode fazer a()- mas com

a = initAll()

a variável aobterá o valor de retorno da initAllfunção executada

Andris
fonte
8

Estou 6 anos atrasado, mas acho que isso poderia ter sido explicado de forma muito mais simples do que as respostas acima.

Então aqui está o TLDR ; ou vista aérea ao chamar funções usando e não usando ()'s

Vamos pegar esta função, por exemplo:

function foo(){
return 123;
}

se você logar "foo" - sem ()

console.log(foo); 

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

Usando nenhum ()meio para buscar a própria função . Você faria isso se quiser que seja repassado como um retorno de chamada.


se você logar "foo ()" - com ()

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

Usar ()depois de uma função significa executar a função e retornar seu valor .

Garrettmac
fonte