Warum schreibt babel den importierten Funktionsaufruf auf (0, fn) (…) um?

100

Gegeben eine Eingabedatei wie

import { a } from 'b';

function x () {
  a()
}

babel wird es kompilieren

'use strict';

var _b = require('b');

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

Beim Kompilieren im Loose-Modus wird der Funktionsaufruf jedoch als ausgegeben _b.a();

Ich habe einige Nachforschungen angestellt, wo der Komma-Operator hinzugefügt wird, in der Hoffnung, dass es einen Kommentar gibt, der dies erklärt. Der Code, der für das Hinzufügen verantwortlich ist, ist hier .

Will Smith
quelle
4
Sie hätten tun sollen _b.a.call(), um die Absicht klar zu machen.
Bergi
@Bergi Ich bin sicher, der Grund, warum sie es mit (0,) tun, ist, Platz im transpilierten Code zu sparen.
Andy

Antworten:

138

(0, _b.a)()stellt sicher, dass die Funktion _b.amit thisset auf das globale Objekt aufgerufen wird (oder wenn der strikte Modus aktiviert ist, auf undefined). Wenn Sie _b.a()direkt anrufen , _b.awird mit thisset to aufgerufen _b.

(0, _b.a)(); ist äquivalent zu

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

( ,Dies ist der Kommaoperator, siehe https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator ).

Rob W.
quelle
3
Danke für den Link. ging so oft darüber hinweg und beschloss schließlich herauszufinden, was los war.
Theflowersoftime
@RobW Ich würde denken, dass das Hinzufügen var _a = (0, _b.a)am Anfang der Datei und das anschließende Aufrufen _ain vielen Fällen mehr Speicherplatz sparen würden. Irgendeine Idee, dass sie das nicht getan haben?
Andy
1
@Andy Ihr Vorschlag kann Nebenwirkungen haben, z. B. wann _b.aein (dynamischer) Getter ist.
Rob W
@RobW Ich verstehe, Sie sagen also, Sie sollten mögliche Nebenwirkungen vermeiden, bis die Funktion aufgerufen werden muss.
Andy
Beachten Sie, dass Module immer strenger Code sind, also immer this === undefinedund Sie müssen nicht einmal das globale Objekt erwähnen
Bergi
22

Der Kommaoperator wertet jeden seiner Operanden aus (von links nach rechts) und gibt den Wert des letzten Operanden zurück.

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

Schauen wir uns also ein Beispiel an:

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

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

Jetzt ist in fooMethode thisgleich a(weil an fooangehängt ist a). Wenn Sie also a.foo(direkt anrufen , wird die falseKonsole angemeldet.

Aber wenn Sie angerufen würden (0, a.foo)(). Der Ausdruck (0, a.foo)wertet jeden seiner Operanden aus (von links nach rechts) und gibt den Wert des letzten Operanden zurück. Mit anderen Worten, (0, a.foo)ist äquivalent zu

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

Da diese Funktion nicht mehr an irgendetwas gebunden ist, thisist sie das globale Objekt window. Deshalb meldet es sich truebeim Anruf in der Konsole an (0, a.foo)().

Huong Nguyen
quelle
Das Ausführen console.log(this === window);in der Dev-Konsole protokolliert den Druck nicht mehr.
Kushdilip
2
Das hat mich umgehauen. Der Schlüssel hier ist, dass der Komma-Operator "den Wert des letzten Operanden zurückgibt" - der "Wert" hier ist die Funktion selbst ohne das enthaltene übergeordnete Element -, sodass foo nicht mehr in a lebt.
Martinp999