CJS和ES6模块之间的语法差异

7
在CJS模块中,我会使用exportvar plugin = require('plugin');来进行导出/导入操作。
在ES6模块中,我会使用exportimport * as plugin from 'plugin';来进行导出/导入操作。
还有其他语法差异吗?上述差异是否正确? export defaultexport *是什么意思?

1
在CJS中,export(和module.export)只是一个变量。在ES6中,export是一个关键字,并且在语言中有自己的语法! - Bergi
@Bergi 谢谢,很有趣。还有一个有趣的答案需要花费一些时间去学习。 - Rikard
1个回答

34

CommonJS模块和ES6模块非常相似,但它们有一些非常重要的差异需要注意。直接回答您的问题:

var plugin = require('plugin');

在ES6中等同于两者都是

// Import all named exports of 'plugin'.
import * as plugin from 'plugin';

和/或

// Import default export of 'plugin'.
import plugin from 'plugin';

// an alias of
import {default as plugin} from 'plugin';

但这取决于'plugin'是如何编写的,以及它是否使用了ES6export或CommonJS module.exports进行编写。

CommonJS模块

CommonJS导入只有一个导出对象。该对象可以是函数、对象或任何其他类型。通常情况下,CommonJS模块会这样做。

exports.foo = ...;
exports.bar = ...;

导出命名属性。它们还可以导出一个“默认”对象

module.exports = function(){};

核心问题在于,如果您想要默认导出和命名导出两个功能,则唯一的选择是将属性直接放到默认导出上。

ES6模块

对于ES6模块,命名导出和默认导出的概念完全分离。例如:

export var foo = ...;
export var bar = ...;
export default function fn(){};

主要区别在于

fn.foo !== foo;

使用这个示例,有两种情况。

插件使用了ES6 export

import * as plugin from 'plugin';

plugin.foo === ...;
plugin.bar === ...;
typeof plugin === 'object';

import plugin from 'plugin';

plugin.foo === undefined;
plugin.bar === undefined;
typeof plugin === 'function';

使用 CommonJS 的插件 module.exports

import * as plugin from 'plugin';

plugin.foo === ...;
plugin.bar === ...;
typeof plugin === 'object';

import plugin from 'plugin';

plugin.foo === ...;
plugin.bar === ...;
typeof plugin === 'function';

实时绑定的导入/导出

在您的示例中,另一个主要区别是plugin是实时绑定。这意味着,如果稍后在模块内更新了它,它会自动更新您的导入内容,例如:

// plugin.js

export var foo = 'foo';

export function update(){
    foo = 'bar';
}

// other.js

import {foo, update} from 'plugin';

foo === 'foo';

update();

foo === 'bar'

如果你不这样做,那将不是这种情况。

var foo = require('plugin').foo;
var update = require('plugin').update;

1
这是一个非常好的回答!+1。我能在Node.js或io.js中的同一项目中使用commonjs和ES6语法吗(我想应该可以,但不知道是否存在我不知道的问题)?Commonsjs模块会随着时间的推移消失吗(也许这是一个主观的问题...)? - Rikard
还发现了一篇有趣的Gist/文章:https://gist.github.com/domenic/4748675 - Rikard
你绝对可以在ES6中使用ES5模块。我不能确定Traceur是否可以,但是当你使用import语法时,Babel会包含一个标准的互操作性层,检查你是否正在导入ES6模块或ES5模块。 - loganfsmyth
这是一个用于演示以上理论的代码仓库:https://github.com/upupming/cjs-vs-esm - upupming

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接