js 一直没有模块系统. 无法将一个大程序拆分成相互依赖的小文件.再用简单的方法拼装起来. 对开发大型复杂项目形成了巨大的障碍.

其他语言都有模块系统:

  • Ruby: require
  • Python: import
  • CSS: @import

ES6 之前: 社区定制了一些模块加载方案. 主要有 commonjs 和 amd 两种. commonjs 用于服务器. amd 用于浏览器.

ES6 实现了模块功能.非常简单.完全可以成为浏览器和服务器的通用模块解决方案.

模块基础知识

每个es6 模块 都是一个 包含js代码的文件. 模块本质就是一段脚本.

ES6 模块设计思想

尽量静态化. 使得 编译时就能确定模块的依赖关系. 以及输入和输出的变量.

运行时加载

// CommonJS模块
let { stat, exists, readFile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

上面代码 实际上是 整体加载fs模块. 也就是加载 fs 的所有方法. 生成一个对象: fs. 然后用这个对象 去读取上面三个方法. 这就叫运行时加载. 因为只有运行时候才能 得到这个对象. 导致完全没有办法在编译时做静态优化

编译时加载

ES6 模块不是对象. 而是通过 export 目录显示的输出代码. 再通过import 输入.

// ES6模块
import { stat, exists, readFile } from 'fs';

代码实际是 从fs模块加载 三个方法.其他的不加载. 这就是编译时加载 / 静态加载. 效果要比 commonjs高. 这也导致了 没法引用es6模块本身. 因为它不是对象.

export 命令

模块主要由两个命令组成. export 和 import. export: 规定模块的对外接口. import: 输入其他模块提供的功能

一个模块 就是一个独立文件. 该文件内部的所有变量. 外部无法获取. 如果你希望 外部能读取某个模块内部的某个变量. 就必须用 export关键字来输出该变量.

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};

import 命令

用export命令 定义了模块的对外接口后.其他js就可以通过import 命令加载这个模块了..

// main.js
import {firstName, lastName, year} from './profile';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}