Existem várias maneiras diferentes de chamar uma função sem parênteses.
Vamos supor que você tenha essa função definida:
function greet() {
console.log('hello');
}
A seguir, siga algumas maneiras de ligar greetsem parênteses:
1. Como Construtor
Com newvocê pode invocar uma função sem parênteses:
new greet; // parentheses are optional in this construct.
Do MDN no newoprator :
Sintaxe
new constructor[([arguments])]
2. Como toStringou valueOfImplementação
toStringe valueOfsão métodos especiais: eles são chamados implicitamente quando uma conversão é necessária:
var obj = {
toString: function() {
return 'hello';
}
}
'' + obj; // concatenation forces cast to string and call to toString.
Você poderia (ab) usar esse padrão para chamar greetsem parênteses:
'' + { toString: greet };
Ou com valueOf:
+{ valueOf: greet };
valueOfe toStringsão chamados de fato do método @@ toPrimitive (desde ES6) e, portanto, você também pode implementar esse método:
+{ [Symbol.toPrimitive]: greet }
"" + { [Symbol.toPrimitive]: greet }
2.b Substituição valueOfno protótipo de função
Você pode seguir a ideia anterior para substituir o valueOfmétodo no Functionprotótipo :
Function.prototype.valueOf = function() {
this.call(this);
// Optional improvement: avoid `NaN` issues when used in expressions.
return 0;
};
Depois de fazer isso, você pode escrever:
+greet;
E embora haja parênteses envolvidos na linha, a chamada de acionamento real não tem parênteses. Veja mais sobre isso no blog "Chamando métodos em JavaScript, sem realmente chamá-los"
3. Como gerador
Você pode definir uma função de gerador (com *), que retorna um iterador . Você pode chamá-lo usando a sintaxe de propagação ou com a for...ofsintaxe.
Primeiro, precisamos de uma variante geradora da greetfunção original :
function* greet_gen() {
console.log('hello');
}
E então a chamamos sem parênteses, definindo o método @@ iterator :
[...{ [Symbol.iterator]: greet_gen }];
Normalmente, os geradores teriam uma yieldpalavra - chave em algum lugar, mas não é necessário para a função ser chamada.
A última instrução chama a função, mas isso também pode ser feito com a desestruturação :
[,] = { [Symbol.iterator]: greet_gen };
ou uma for ... ofconstrução, mas possui parênteses próprios:
for ({} of { [Symbol.iterator]: greet_gen });
Observe que você também pode fazer o acima com a greetfunção original , mas ela acionará uma exceção no processo, após a greet execução (testada no FF e no Chrome). Você pode gerenciar a exceção com um try...catchbloco.
4. Como Getter
@ jehna1 tem uma resposta completa sobre isso, então dê-lhe crédito. Aqui está uma maneira de chamar uma função sem parênteses no escopo global, evitando o método descontinuado__defineGetter__ . Ele usa em seu Object.definePropertylugar.
Precisamos criar uma variante da greetfunção original para isso:
Object.defineProperty(window, 'greet_get', { get: greet });
E depois:
greet_get;
Substitua windowpor qualquer que seja seu objeto global.
Você poderia chamar a greetfunção original sem deixar rastros no objeto global como este:
Object.defineProperty({}, 'greet', { get: greet }).greet;
Mas alguém poderia argumentar que temos parênteses aqui (embora eles não estejam envolvidos na invocação real).
5. Como função de tag
Desde o ES6, você pode chamar uma função passando um literal de modelo com esta sintaxe:
greet``;
Consulte "Literais de modelo marcados" .
6. Como manipulador de proxy
Desde o ES6, você pode definir um proxy :
var proxy = new Proxy({}, { get: greet } );
E a leitura de qualquer valor da propriedade chamará greet:
proxy._; // even if property not defined, it still triggers greet
Existem muitas variações disso. Mais um exemplo:
var proxy = new Proxy({}, { has: greet } );
1 in proxy; // triggers greet
7. Como verificador de instância
O instanceofoperador executa o @@hasInstancemétodo no segundo operando, quando definido:
1 instanceof { [Symbol.hasInstance]: greet } // triggers greet