Il existe plusieurs façons d'appeler une fonction sans parenthèses.
Supposons que cette fonction soit définie:
function greet() {
console.log('hello');
}
Ensuite, voici quelques façons d'appeler greetsans parenthèses:
1. En tant que constructeur
Avec newvous pouvez invoquer une fonction sans parenthèses:
new greet; // parentheses are optional in this construct.
De MDN sur l' newoprateur :
Syntaxe
new constructor[([arguments])]
2. Au fur toStringet à mesure de la valueOfmise en œuvre
toStringet valueOfsont des méthodes spéciales: elles sont appelées implicitement lorsqu'une conversion est nécessaire:
var obj = {
toString: function() {
return 'hello';
}
}
'' + obj; // concatenation forces cast to string and call to toString.
Vous pouvez (ab) utiliser ce modèle pour appeler greetsans parenthèses:
'' + { toString: greet };
Ou avec valueOf:
+{ valueOf: greet };
valueOfet toStringsont en fait appelés à partir de la méthode @@ toPrimitive (depuis ES6), et vous pouvez donc également implémenter cette méthode:
+{ [Symbol.toPrimitive]: greet }
"" + { [Symbol.toPrimitive]: greet }
2.b Remplacement valueOfdu prototype de fonction
Vous pouvez prendre l'idée précédente pour remplacer la valueOfméthode sur le Functionprototype :
Function.prototype.valueOf = function() {
this.call(this);
// Optional improvement: avoid `NaN` issues when used in expressions.
return 0;
};
Une fois que vous avez fait cela, vous pouvez écrire:
+greet;
Et bien qu'il y ait des parenthèses impliquées sur la ligne, l'invocation de déclenchement réelle n'a pas de parenthèses. Voir plus à ce sujet dans le blog "Appeler des méthodes en JavaScript, sans vraiment les appeler"
3. En tant que générateur
Vous pouvez définir une fonction de générateur (avec *), qui renvoie un itérateur . Vous pouvez l'appeler en utilisant la syntaxe étendue ou avec la for...ofsyntaxe.
Nous avons d'abord besoin d'une variante de générateur de la greetfonction d' origine :
function* greet_gen() {
console.log('hello');
}
Et puis nous l'appelons sans parenthèses en définissant la méthode @@ itérateur :
[...{ [Symbol.iterator]: greet_gen }];
Normalement, les générateurs auraient un yieldmot - clé quelque part, mais il n'est pas nécessaire d'appeler la fonction.
La dernière instruction appelle la fonction, mais cela pourrait également être fait avec la déstructuration :
[,] = { [Symbol.iterator]: greet_gen };
ou une for ... ofconstruction, mais elle a ses propres parenthèses:
for ({} of { [Symbol.iterator]: greet_gen });
Notez que vous pouvez également faire ce qui précède avec la greetfonction d' origine , mais cela déclenchera une exception dans le processus, après greet avoir été exécuté (testé sur FF et Chrome). Vous pouvez gérer l'exception avec un try...catchbloc.
4. En tant que Getter
@ jehna1 a une réponse complète à ce sujet, alors donnez-lui du crédit. Voici un moyen d'appeler une fonction sans parenthèses sur la portée globale, en évitant la méthode obsolète__defineGetter__ . Il utilise à la Object.definePropertyplace.
Nous devons créer une variante de la greetfonction d' origine pour cela:
Object.defineProperty(window, 'greet_get', { get: greet });
Puis:
greet_get;
Remplacez windowpar quel que soit votre objet global.
Vous pouvez appeler la greetfonction d' origine sans laisser de trace sur l'objet global comme ceci:
Object.defineProperty({}, 'greet', { get: greet }).greet;
Mais on pourrait dire que nous avons des parenthèses ici (bien qu'ils ne soient pas impliqués dans l'invocation réelle).
5. Comme fonction d'étiquette
Depuis ES6, vous pouvez appeler une fonction en lui passant un modèle littéral avec cette syntaxe:
greet``;
Voir "Littéraux de modèle balisés" .
6. En tant que gestionnaire de proxy
Depuis ES6, vous pouvez définir un proxy :
var proxy = new Proxy({}, { get: greet } );
Et puis la lecture de toute valeur de propriété invoquera greet:
proxy._; // even if property not defined, it still triggers greet
Il en existe de nombreuses variantes. Un autre exemple:
var proxy = new Proxy({}, { has: greet } );
1 in proxy; // triggers greet
7. En tant que vérificateur d'instance
L' instanceofopérateur exécute la @@hasInstanceméthode sur le deuxième opérande, lorsqu'il est défini:
1 instanceof { [Symbol.hasInstance]: greet } // triggers greet