现状
现行的大部分 javascript 版本以及浏览器对于他们来说, 他们有可能不支持这个module
, 通常当遇到 import 或者 export 就会报语法错误. 当然为了能够解决 js 代码里的各种冲突, 大家也是想出来其他的替代方法实现了 module
的功能. 现有的比较常见的就有
- CommonJS 典型的实现就是在 nodejs 里具体有下面的一些特征
- 语法简洁
- 同步加载
- 主要用在服务器端
- AMD 也就是异步加载模块, 典型的实现就是 RequireJS ,有下面一些特点:
- 语法相对复杂些,能够避免使用
eval()
- 异步加载
- 浏览器端使用
- 语法相对复杂些,能够避免使用
上面就是大概介绍,有兴趣可以看这里
下面来说说从 es6开始对于 module 的支持以及实现
ES6模块
ES6试图设计一种模块的格式,它能够同时满足对于 CommonJS 和 AMD 模块的使用习惯:
- 类似 CommonJS 它的语法简洁,单独的 exports就好, 支持循环依赖
- 类似 AMD 的异步加载,模块可配置.
同时还有他们2个没有的一些特性:
- 语法要比 CommonJS 还简洁
- 结构是可以静态分析的(满足静态验证,优化等)
- 比 CommonJS 的循环依赖还要赞.
ES6的模块设计分为大概2部分:
- 声明式语法(通过 import 和 export)
- 可编程加载的 API: 能够配置怎么加载模块还有条件加载)
ES6模块语法
有2种模块的声明方式:命名声明(多个模块)和默认声明(单个模块)
命名式声明
一个模块(An ES6 module is a file containing JS code. There’s no special module keyword; 也就是说,所谓的 es6模块就是一个含有 js 代码的 文件, 并没声明特殊的 module字眼) 它能够通过关键字 export
来定义多个内容.这些定义的模块名就是通过不同的前缀来区别. 这个我们就称之为 命名式的模块定义.
看上去就是这样子:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ main.js ------
// 所有的变量名,函数名都是在模块中定义的
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
当然定义的它的方法有很多,但是我感觉这个就是最好的方式, 定义一切你不想暴露在外面世界的内容,然后给他一个前缀关键字 export
,就这样它就是一个模块了.
怎么用呢,这样子的:
//------ main.js ------
import * as lib from 'lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5
而如果换做CommonJS 来写,其实下面的代码我想了很多方法让它看上去更加简洁一些去掉重复的部分.
var sqrt = Math.sqrt;
function square(x) {
return x * x;
}
function diag(x, y) {
return sqrt(square(x) + square(y));
}
// 区别就是这里
module.exports = {
sqrt: sqrt,
square: square,
diag: diag,
};
var square = require('lib').square;
var diag = require('lib').diag;
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
默认声明(每一个模块只有一个)
在 Node 的圈子里通常喜欢一个模块只定义导出一个单个值, 其实通常前端他们也喜欢这样做的.如果在处理对象 model 的时候类和构造函数的时候. 一个对象一个模块. 一个 ES6的模块能够选择一个默认导出
最重要的要导出的值.默认导出的值是最容易导入使用的.
下面的例子, 定义了一个单个的函数:
export default function () { ... };
import myFunc from 'myFunc';
myFunc();
而如果它表示的值是一个类的时候:
export default class { ... };
import MyClass from 'MyClass';
let inst = new MyClass();
注意 默认导出的声明是一个表达式, 它通常没有名字代替的是它通过模块名字来区别.