Почему babel перезаписывает вызов импортированной функции в (0, fn) (…)?

100

Учитывая входной файл, например

import { a } from 'b';

function x () {
  a()
}

Babel скомпилирует это в

'use strict';

var _b = require('b');

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

но при компиляции в свободном режиме вызов функции выводится как _b.a();

Я провел некоторое исследование того, где добавлен оператор запятой, в надежде, что это был комментарий, объясняющий его. Код, отвечающий за его добавление, находится здесь .

Уилл Смит
источник
4
Они должны были сделать _b.a.call()это, чтобы прояснить намерение.
Берги
@Bergi Я уверен, что они использовали (0,), чтобы сэкономить место в транспилированном коде.
Энди
см. также синтаксис JavaScript (0, fn) (args)
Берги

Ответы:

138

(0, _b.a)()гарантирует, что функция _b.aвызывается с thisустановленным глобальным объектом (или, если включен строгий режим, с undefined). Если вы вызываете _b.a()напрямую, то _b.aвызывается с thisустановленным значением _b.

(0, _b.a)(); эквивалентно

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

( ,это оператор запятой, см. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator ).

Роб В
источник
3
спасибо за ссылку. много раз проходил мимо этого и наконец решил выяснить, что происходит.
theflowersoftime
@RobW Я бы подумал, что добавление var _a = (0, _b.a)вверху файла с последующим вызовом _aво многих случаях сэкономит больше места, любая идея, что они этого не сделали?
Энди
1
@Andy Ваше предложение может иметь побочные эффекты, например, когда _b.aявляется (динамическим) получателем.
Роб У
@RobW Понятно, значит, вы говорите, что идея состоит в том, чтобы избежать потенциальных побочных эффектов, пока функция не будет вызвана.
Энди
Обратите внимание, что модули всегда представляют собой строгий код, поэтому он всегда, this === undefinedи вам даже не нужно упоминать глобальный объект
Берги,
22

Оператор запятой оценивает каждый из своих операндов (слева направо) и возвращает значение последнего операнда.

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

Итак, давайте посмотрим на пример:

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

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

Теперь в fooметоде thisравно a(потому что fooприкреплено к a). Поэтому, если вы позвоните a.foo(напрямую, он войдет falseв консоль.

Но, если вам позвонят (0, a.foo)(). Выражение (0, a.foo)будет оценивать каждый из своих операндов (слева направо) и возвращает значение последнего операнда. Другими словами, (0, a.foo)эквивалентно

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

Поскольку эта функция больше ни к чему не привязана, thisэто глобальный объект window. Вот почему он входит trueв консоль при вызове (0, a.foo)().

Хуонг Нгуен
источник
при запуске console.log(this === window);в консоли разработчика печать больше не ведется.
kushdilip
3
Это поразило меня. Ключевым моментом здесь является то, что оператор Comma «возвращает значение последнего операнда» - «значение» здесь - это сама функция без содержащего ее родителя, поэтому foo больше не живет внутри a.
martinp999 07