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 .


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


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 ).


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)().


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.