Perché babel riscrive la chiamata di funzione importata in (0, fn) (…)?


100

Dato un file di input come

import { a } from 'b';

function x () {
  a()
}

babel lo compilerà in

'use strict';

var _b = require('b');

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

ma quando viene compilato in modalità libera, la chiamata alla funzione viene emessa come _b.a();

Ho fatto alcune ricerche su dove viene aggiunto l'operatore virgola nella speranza che ci fosse un commento che lo spiegasse. Il codice responsabile dell'aggiunta è qui .


4
Avrebbero dovuto farlo _b.a.call()per rendere chiara l'intenzione.
Bergi

@Bergi Sono sicuro che il motivo per cui lo hanno con (0,) è per risparmiare spazio nel codice traspilato.
Andy


Risposte:


138

(0, _b.a)()assicura che la funzione _b.asia chiamata con thisimpostato sull'oggetto globale (o se la modalità rigorosa è abilitata, su undefined). Se si dovesse chiamare _b.a()direttamente, _b.aviene chiamato con thisimpostato su _b.

(0, _b.a)(); è equivalente a

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

( ,è l'operatore virgola, vedere https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator ).


3
grazie per il link. ci è passato sopra tante volte e alla fine ha deciso di scoprire cosa stava succedendo.
theflowersoftime

@ RobW, penserei che l'aggiunta var _a = (0, _b.a)all'inizio del file e quindi la chiamata _asalverebbe più spazio in molti casi, idea che non l'hanno fatto?
Andy

1
@ Anddy Il tuo suggerimento potrebbe avere effetti collaterali, ad esempio quando _b.aè un getter (dinamico).
Rob W,

@ RobW Capisco, quindi stai dicendo che l'idea è di evitare potenziali effetti collaterali fino a quando la funzione non deve essere chiamata.
Andy

Si noti che i moduli sono sempre un codice rigoroso, quindi è sempre this === undefinede non è nemmeno necessario menzionare l'oggetto globale
Bergi

22

L'operatore virgola valuta ciascuno dei suoi operandi (da sinistra a destra) e restituisce il valore dell'ultimo operando.

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

Quindi, vediamo un esempio:

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

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

Ora, nel foometodo, thisè uguale a a(perché fooè attaccato a a). Quindi, se chiami a.foo() direttamente, accederà falsealla console.

Ma, se fossi chiamata (0, a.foo)(). L'espressione (0, a.foo)valuterà ciascuno dei suoi operandi (da sinistra a destra) e restituirà il valore dell'ultimo operando. In altre parole, (0, a.foo)è equivalente a

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

Poiché questa funzione non è più collegata a nulla, thisè l'oggetto globale window. Ecco perché accede truealla console durante la chiamata (0, a.foo)().


l'esecuzione console.log(this === window);nella console di sviluppo non registra più la stampa.
kushdilip

2
Questo mi stava sbalordendo. La chiave qui è che l'operatore Virgola "restituisce il valore dell'ultimo operando" - il "valore" qui è la funzione stessa assente dal genitore che lo contiene - quindi foo non vive più all'interno di a.
martinp999,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.