Dlaczego babel przepisuje wywołanie funkcji importowanej na (0, fn) (…)?


100

Biorąc pod uwagę plik wejściowy, taki jak

import { a } from 'b';

function x () {
  a()
}

babel skompiluje go do

'use strict';

var _b = require('b');

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

ale po kompilacji w trybie luźnym wywołanie funkcji jest wyświetlane jako _b.a();

Zrobiłem kilka badań, gdzie dodano operator przecinka, mając nadzieję, że był komentarz wyjaśniający to. Kod odpowiedzialny za jego dodanie znajduje się tutaj .


4
Powinni zrobić, _b.a.call()aby jasno określić zamiar.
— Bergi

@Bergi Jestem pewien, że powodem tego z (0,) jest oszczędność miejsca w transpilowanym kodzie.
— Andy


Odpowiedzi:


138

(0, _b.a)()zapewnia, że ​​funkcja _b.ajest wywoływana z thisustawieniem na obiekt globalny (lub, jeśli włączony jest tryb ścisły, na undefined). Jeśli miałbyś zadzwonić _b.a()bezpośrednio, _b.awywoływany jest z thisustawionym na _b.

(0, _b.a)(); jest równa

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

(the ,jest operatorem przecinka, patrz https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator ).


3
dzięki za link. Pominąłem to tyle razy i ostatecznie postanowiłem dowiedzieć się, co się dzieje.
— theflowersoftime

@RobW Myślę, że dodanie var _a = (0, _b.a)na początku pliku, a następnie wywołanie _apozwoliłoby zaoszczędzić więcej miejsca w wielu przypadkach, jakikolwiek pomysł, że tego nie zrobili?
— Andy

1
@Andy Twoja sugestia może mieć skutki uboczne, np. Kiedy _b.a(dynamiczny) getter.
— Rob W

@RobW Rozumiem, więc mówisz, że pomysł polega na unikaniu potencjalnych skutków ubocznych, dopóki funkcja nie będzie musiała zostać wywołana.
— Andy

Zauważ, że moduły są zawsze ścisłym kodem, więc tak jest zawsze this === undefinedi nie musisz nawet wspominać o globalnym obiekcie
— Bergi

22

Operator przecinka ocenia każdy z jego operandów (od lewej do prawej) i zwraca wartość ostatniego operandu.

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

Zobaczmy więc przykład:

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

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

Teraz w foometodzie thisrówna się a(ponieważ foojest do niej przywiązana a). Więc jeśli zadzwonisz a.foo(bezpośrednio), zaloguje się falsedo konsoli.

Ale gdybyś został wezwany (0, a.foo)(). Wyrażenie (0, a.foo)oceni każdy z jego operandów (od lewej do prawej) i zwróci wartość ostatniego operandu. Innymi słowy, (0, a.foo)jest równoważne

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

Ponieważ ta funkcja nie jest już do niczego przypisana, thisjest obiektem globalnym window. Dlatego loguje się truedo konsoli, gdy dzwonisz (0, a.foo)().


uruchomienie console.log(this === window);w konsoli programisty nie rejestruje już drukowania.
— kushdilip

2
To mnie zaskoczyło. Kluczem tutaj jest to, że operator przecinka „zwraca wartość ostatniego operandu” - „wartość” jest tutaj samą funkcją, w której nie ma jej zawierającego rodzica - więc foo nie istnieje już wewnątrz a.
— martinp999
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.