Pourquoi babel réécrit-il l'appel de fonction importé vers (0, fn) (…)?

100

Étant donné un fichier d'entrée comme

import { a } from 'b';

function x () {
  a()
}

babel le compilera pour

'use strict';

var _b = require('b');

function x() {
  (0, _b.a)();
}

mais une fois compilé en mode lâche, l'appel de fonction est émis comme _b.a();

J'ai fait des recherches pour savoir où l'opérateur virgule est ajouté dans l'espoir qu'un commentaire l'explique. Le code chargé de l'ajouter est ici .

Will Smith
la source
4
Ils auraient dû faire _b.a.call()pour que l'intention soit claire.
Bergi
@Bergi Je suis sûr que la raison pour laquelle ils utilisent (0,) est d'économiser de l'espace dans le code transpilé.
Andy
voir aussi la syntaxe JavaScript (0, fn) (args)
Bergi

Réponses:

138

(0, _b.a)()garantit que la fonction _b.aest appelée avec thisset sur l'objet global (ou si le mode strict est activé, sur undefined). Si vous appelez _b.a()directement, alors _b.aest appelé avec thisla valeur _b.

(0, _b.a)(); est équivalent à

0; // Ignore result
var tmp = _b.a;
tmp();

(il ,s'agit de l'opérateur virgule, voir https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator ).

Rob W
la source
3
Merci pour le lien. passé tant de fois et a finalement décidé de découvrir ce qui se passait.
theflowersoftime
@RobW Je pense que l'ajout var _a = (0, _b.a)en haut du fichier puis l'appel _apermettrait d'économiser plus d'espace dans de nombreux cas, aucune idée qu'ils n'ont fait cela?
Andy
1
@Andy Votre suggestion peut avoir des effets secondaires, par exemple quand _b.aest un getter (dynamique).
Rob W
@RobW Je vois, donc vous dites que l'idée est d'éviter les effets secondaires potentiels jusqu'à ce que la fonction doive être appelée.
Andy
Notez que les modules sont toujours du code strict, donc c'est toujours this === undefinedet vous n'avez même pas besoin de mentionner l'objet global
Bergi
22

L'opérateur virgule évalue chacun de ses opérandes (de gauche à droite) et renvoie la valeur du dernier opérande.

console.log((1, 2)); // Returns 2 in console
console.log((a = b = 3, c = 4)); // Returns 4 in console

Alors, voyons un exemple:

var a = {
  foo: function() {
    console.log(this === window);
  }
};

a.foo(); // Returns 'false' in console
(0, a.foo)(); // Returns 'true' in console

Maintenant, dans la foométhode, thisest égal à a(car fooest attaché à a). Donc, si vous appelez a.foo() directement, il se connectera falseà la console.

Mais, si vous étiez appelé (0, a.foo)(). L'expression (0, a.foo)évaluera chacun de ses opérandes (de gauche à droite) et retournera la valeur du dernier opérande. En d'autres termes, (0, a.foo)équivaut à

function() {
  console.log(this === window);
}

Puisque cette fonction n'est plus attachée à rien, thisc'est l'objet global window. C'est pourquoi il se connecte trueà la console lors de l'appel (0, a.foo)().

Huong Nguyen
la source
l'exécution console.log(this === window);dans la console de développement ne consigne plus l'impression.
kushdilip
2
C'était époustouflant. La clé ici est que l'opérateur Virgule "renvoie la valeur du dernier opérande" - la "valeur" ici est la fonction elle-même sans son parent contenant - donc foo ne vit plus à l'intérieur d'un.
martinp999