Skip to content

CommonJS和ES6 Module #27

Description

@cookiepool

CommonJS

主要用在服务器端,Node.js目前使用的规范,使用module.exports或者exports导出,require引入。

为了避免出问题,我们一般使用module.exports(本质是一个对象)来导出,因为exports是对module.exports的引用。当你的exports的引用对象不再指向exports时,导出就会出现问题

基本的用法

  • export_test.js
let a = 100;
let b = [1, 2, 3];
let c = {
  name: 'lee',
  age: 25
};

function add(a, b) {
  return a + b;
}

module.exports = {
  a,
  b,
  c,
  add
}
  • import_test.js
const obj = require('./export_test.js');

console.log(obj.add(2, 3));  // 5
console.log(obj.a); // 100

使用exports

这里使用exports的话就要改变一下写法了,前面说过exports是对module.exports的一个引用,你最终导出的还是module.exports,而不是说你写exports导出的就是exports。所以建议在使用时尽量使用module.exports。

  • 下面这种写法会报错

这个基于上面export_test.js的内容来说的

// exports的指向变成了一个包含a,b,c,add的对象,但是CommonJS默认导出的是module.exports,所以require过后也取不到a,b,c,add这些。
exports = {
  a,
  b,
  c,
  add
}
  • 正确的写法
exports.a = a;
exports.b = b;
exports.c = c;
exports.add = add;
  • 三种正确的导出方法
// 三种导出方法,取其中一个即可
/* 第一种导出方法 */
module.exports = {
  a,
  b,
  c,
  add
}

/* 第二种导出方法 */
module.exports.a = a;
module.exports.b = b;
module.exports.c = c;
module.exports.add = add;

/* 第三种导出方法 */
exports.a = a;
exports.b = b;
exports.c = c;
exports.add = add;

其它注意点

  • 混合使用
// 混合使用
exports.a = a;
exports.b = b;
module.exports.c = c;
module.exports.add = add;

这样也是可以的。

特点

CommonJS 加载模块是同步的,所以只有加载完成才能执行后面的操作。像Node.js主要用于服务器的编程,加载的模块文件一般都已经存在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式,所以CommonJS规范比较适用。

ES6 Module

ES6 Module是ES6提出来的标准,使用export或者export default来导出,使用import来导入。node.js从13.2.0过后开始支持ES Module了,不过需要把你的js文件命名为mjs,或者在你的项目的package.json中声明"type": "module",我这儿为了方便,更新了node.js为13.5.0,同时文件后缀为mjs。

基础用法

  • export_test.mjs
let a = 100;
let b = [1, 2, 3];
let c = {
  name: 'lee',
  age: 25
};

function add(a, b) {
  return a + b;
}

export {a, b, c, add};
  • import_test.mjs
import { a, b, c, add } from './export_test.mjs';
console.log(a); // 100
console.log(b); // [1, 2, 3]
console.log(c); // {name: 'lee',age: 25}
console.log(add(2, 3));  // 5

注:使用上面的export导出对象时,另一个模块的import的花括号里面的变量名必须跟导出模块里面的变量名相同,不然会报错,变量的书写次序可以不同。

使用export default

  • 把export_test.mjs的导出语句写成这种
export default {a, b, c, add};
  • 然后呢修改import_test.mjs的引入语句
import Test from './export_test.mjs';
console.log(Test.a); // 100
console.log(Test.b); // [1, 2, 3]
console.log(Test.c); // {name: 'lee',age: 25}
console.log(Test.add(2, 3));  // 5

其它用法

注意:一个模块里面export语句可以有多个,但是export default只能有一个。

  • 多个export语句
// 多个export语句
export const a = 12;

export function reduce(a, b) {
  return a - b;
}

// 注意这样写是不行的
const c = 'hello';
export c;

// 另一个模块导入
import {a, reduce} from './export_test.mjs';

console.log(a);
console.log(reduce(5, 2));
  • 多个export语句在另一个模块导入时可以全部封装为一个对象
// 这样也是可以的
import * as Test from './export_test.mjs';

console.log(Test.a);
console.log(Test.reduce(5, 2));
  • export default注意事项
// 这样写莫得问题,相当于导出一个函数对象
export default function add(a, b) {
  return a + b;
}

// 这两种都是错误写法
export default const j = 100;
export default let k = 100;


// 这样写就没问题了
let j = 100;
export default j;

特点

ES6的模块不是对象,import命令会被 JavaScript 引擎静态分析,在编译时就引入模块代码,而不是在代码运行时加载,所以无法实现条件加载。也正因为这个,使得静态分析成为可能。

23232.png

参考资料

AMD, CMD, CommonJS和UMD
再次梳理AMD、CMD、CommonJS、ES6 Module的区别
前端模块化:CommonJS,AMD,CMD,ES6
import、require、export、module.exports 混合使用详解
Javascript模块化七日谈

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions