zwhu / blog

嘛,写 blog 也要遵守基本法。
MIT License
66 stars 2 forks source link

被 babel 翻译后的 ES6 Module #26

Open zwhu opened 8 years ago

zwhu commented 8 years ago

写这篇文章的起因是源于和同事的一次讨论, 同事的周报上说在写 React 组件的时候, A 组件 Import 了 B 组件, 同时在 B 组件中也 Import 了A 组件,此情况就形成了循环依赖,在 A 组件中引入的 B 组件为 undefined。但是在我之前的印象中( #16) ,此时的 B 组件应该为空对象 {}

一言不合,看看 babel 把 ES6 的 Module 翻译成什么:


// =================
// a.js
// =================
import b from './b'

function foo() {
    b.bar();
}

export default foo

// =================
// b.js
// =================
import a from './a'

console.log(a)

上面一段代码,如果是 node 的写法,在读取 a.js 的时候就被 cache 为一个空对象了,此时在 b 中读取a一定会是一个空对象,但是通过babel-clia.jsb.js翻译成ES5` 之后再看看:


babel a.js > a.bundle.js
babel b.js > b.bundle.js

// =================
// a.bundle.js
// 把 require './b' 改成 './b.bundle'
// =================
'use strict';

Object.defineProperty(exports, "__esModule", {
    value: true
});

var _b = require('./b.bundle');

var _b2 = _interopRequireDefault(_b);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function foo() {
    _b2.default.bar();
}

exports.default = foo;

// =================
// b.bundle.js
// 把 require './a' 改成 './a.bundle'
// =================
'use strict';

var _a = require('./a.bundle');

var _a2 = _interopRequireDefault(_a);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

console.log(_a2.default);

从上面两段代码可以看到 babel 把 export default foo 转成 exports.default = foo , 在 b.bundle.js 中根据 #16 中分析的可以知道 _a 的值为 {},所以此时 _a2.default 的值为 _a.default, _a 为 {}, 那么 {}.defaultundefined

其实如果按照 ES6 的标准,ES6 module 的出现就天然的解决了循环依赖的问题,babel 对 ES6 的module 的支持还是有些问题的,只是简单的翻译成 common.js 的方式。😄