ES6模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系以及输入和输出的变量。CommonJs和AMD模块,都是只有在运行时确定这些东西,所以无法进行编译时的‘静态优化’。

ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入(这种方式称为编译时加载或者静态加载)。也就是说ES6可以在编译时完成模块加载,效率比CommonJS的方式要高。

严格模式

ES6模块自动采用严格模式,严格模式的的限制有:

export命令

export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。 export命令输出变量:

//profile.js
export var firstName = 'Nichael';
export var lastName = 'Jackson';
export var year = 1986;

也可以采用另外一种写法(优先使用这种写法,比较容易的看出输出了那些变量):

//profile.js
var firstName = 'Nichael';
var lastName = 'Jackson';
var year = 1986;

export {firstName, lastName, year};

通常情况下,export输出的变量就是本来的名字,但可以使用as关键字重命名。

function v1(){}
function v2(){}

export {
    v1 as streamV1,
    v2 as streamV2,
    v2 as streamLatestVersion
}

上面代码使用as关键字重命名了函数v1和v2,而且v2可以用不同的名字输出两次

注意:export命令规定的是对外的接口,必须与模块内部的变量建立一一对应的关系

export 1//报错
var m = 1;
export m;//报错

正确写法:

//写法1
export var m = 1;
//写法2
var m = 1;
export {m};
//写法3
var n = 1;
export {n as m};

export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。

export var foo = 'bar';
setTimeout(()=>foo = 'baz', 500);

上面代码输出变量foo,值为bar,500 毫秒之后变成baz。这一点与 CommonJS 规范完全不同。CommonJS 模块输出的是值的缓存,不存在动态更新。

export命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错,下一节的import命令也是如此。这是因为处于条件代码块之中,就没法做静态优化了

import

相对于export命令,import可以加载一个模块

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

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

使用as关键字重命名输入的变量

import {lastname as surname} from './profile.js';

import命令输入的变量都是只读的,不允许在加载模块的脚本里面,改写接口

import {a} from './xxx.js'
a = {}; // Syntax Error : 'a' is read-only;

看另外一个例子

import {a} from './xxx.js';
a.foo = 'hello'; //合法操作

上面代码中,a的属性可以成功修改。但这种方式很难查错。建议凡是输入的变量,都当作完全只读

import后面的from指定 模块文件的位置,可以是相对路径或者绝对路径,.js后缀可以省略 。 如果只是模块明,不带路径,那么必须有配置文件告诉JavaScript引擎该模块的位置。

注意:import命令具有提示效果,会提升到整个模块的头部,首先执行

foo();
import {foo} from 'myModule';

以上语法不会报错,因为import的执行早于foo的调用。import命令是在编译阶段执行的,在代码执行之前。 使用import时,(静态执行)不能使用表达式或者变量。

//报错
import {'f' + 'oo'} from 'myModule';
//报错
let moudle = 'myModule';
import {foo} from module;
//报错
if( x === 1){
  import {foo} from 'module1'
} else {
  import {foo} from 'module2'
}

以上语法均报错。

#模块的整体加载

用星号(*)指定一个对象,所以输出值都加载在这个对象上面。

//circle.js
export function area(radius) {
  return Math.PI * radius * radius;
}
export function circumference(radius){
  return 2 * Math.PI * radius;
}

加载该模块,逐一加载

import {area, circumference} from ‘./circle’;

整体加载

import * as circle from './circle';

export default 命令

为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。

// export-default.js
export default function(){
  console.log('foo');
}

默认输出一个函数,其他模块加载该模块是,import命令可以为该函数指定任意名称。

import customeName from './export-default';
customeName(); //foo

上面代码的import命令,可以用任意名称指向export-default.js输出的方法,这时就不需要知道原模块输出的函数名。注意:这时import命令后面,不适用大括号。 export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出。因此export default命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令。

以下写法也是有效的。

//modules.js
function add(x,y) {
  return x*y;
}

export {add as default};
//等同于
//export default add;

//app.js
import {default as foo} from 'modules';
//等同于
//import foo from 'modules';

export default也可以用来输出类。 //MyClass.js export default class {…}

//main.js
import MyClass from 'MyClass';
let o = new MyClass();

export 与 import的复合写法

如果在一个模块之中,先输入后输出同一个模块,import语句可以与export语句写在一起。

export {foo,bar} from 'my_module';
//等同于
import {foo, bar} from 'my_module';
export {foo, bar};

模块的接口改名和整体输出,也可以采用这种写法。

//接口改名
export {foo as myFoo} from 'my_module';
//整体输出
export * from 'my_module';

具体接口名改为默认接口的写法如下

export {es6 as default} from './someModue';
//等同于
import {es6} from './someModule';
export default es6;

默认接口改为具体接口名

export {default as es6} from './someModule';

跨模块常量

const声明的常量只有在当前代码块有效。如果想设置跨模块的常量,可以采用下面写法。

//constants.js
export const A = 1;
export const B = 2;
export const C = 3;

//test.js
import * as constants from './constants';
console.log(constants.A);//1
console.log(constants.B);//2

//test2.js
import {A, B} from './constants';
console.log(A);
console.log(B);

如果常量数量非常多,可以专门创建一个constants目录,将各种常量写在不同的文件里面,保存在该目录下。

// constants/db.js
export const db = {
  url: 'http://my.couchdbserver.local:5984',
  admin_username: 'admin',
  admin_password: 'admin password'
};

// constants/user.js
export const users = ['root', 'admin', 'staff', 'ceo', 'chief', 'moderator'];

然后将这些文件输出的常量,合并到一个js中,index.js

// constants/index.js
export {db} from './db';
export {users} from './users';

使用的时候,直接加载index.js就可以了。

//script.js
import {db, users} from './constants/index';

参考链接:

http://es6.ruanyifeng.com/#docs/module

  1. 寻寻觅觅 -- Christine Welch
  2. Just the Way You Are -- Bruno Mars
  3. Despacito(Remix) -- Luis Fonsi;Daddy Yankee;Justin Bieber
  4. 没有什么不同 -- 曲婉婷
  5. 故乡--许巍
  6. Jar Of Love -- 曲婉婷
  7. I Really Like You -- Carly Rae Jepsen