ES6模块
CommonJS和AMD都是运行时加载。ES6在语言规格层面上实现了模块功能,是编译时加载,完全可以取代现有的CommonJS和AMD规范,可以成为浏览器和服务器通用的模块解决方案。
ES6模块使用——export
(1)导出一个变量
export var name = 'pengpeng';
(2)导出一个函数
export function foo(x, y){}
(3)常用导出方式(推荐)
// person.js
const name = 'dingman';
const age = '18';
const addr = '卡尔斯特森林';
export { firstName, lastName, year };
(4)As用法
const s = 1;
export {
s as t,
s as m,
}
可以利用as将模块输出多次。
ES6模块使用——import
(1)一般用法
import { name, age } from './person.js';
(2)As用法
import { name as personName } from './person.js';
import命令具有提升效果,会提升到整个模块的头部,首先执行,如下也不会报错:
getName();
import { getName } from 'person_module';
(3)整体模块加载 *
//person.js
export name = 'xixi';
export age = 23;
//逐一加载
import { age, name } from './person.js';
//整体加载
import * as person from './person.js';
console.log(person.name);
console.log(person.age);
ES6模块使用——export default
区别
export
命令对外输出了指定名字的变量(变量也可以是函数或类)。
与export default命令的区别:import
命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块对外接口的名称相同。
如果想为输入的变量重新取一个名字,import
命令要使用as
关键字,将输入的变量重命名。
export default
命令,为模块指定默认输出。
使用import
命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。
为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default
命令,为模块指定默认输出。因此export default
命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default
命令。
其实export default,在项目里用的非常多,一般一个Vue组件或者React组件我们都是使用export default命令,需要注意的是使用export default命令时,import是不需要加{}的。而不使用export default时,import是必须加{},示例如下:
//person.js
export function getName() {
...
}
//my_module
import {getName} from './person.js';
-----------------对比---------------------
//person.js
export default function getName(){
...
}
//my_module
import getName from './person.js';
export default其实是导出一个叫做default的变量,所以其后面不能跟变量声明语句。
//错误
export default var a = 1;
值得注意的是我们可以同时使用export 和export default
//person.js
export name = 'dingman';
export default function getName(){
...
}
//my_module
import getName, { name } from './person.js';
前面一直提到,CommonJS是运行时加载,ES6时编译时加载,那么两个有什么本质的区别呢?
ES6模块与CommonJS模块加载区别
ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。所以说ES6是编译时加载,不同于CommonJS的运行时加载(实际加载的是一整个对象),ES6模块不是对象,而是通过export命令显式指定输出的代码,输入时也采用静态命令的形式:
//ES6模块
import { basename, dirname, parse } from 'path';
//CommonJS模块
let { basename, dirname, parse } = require('path');
以上这种写法与CommonJS的模块加载有什么不同?
- 当require path模块时,其实 CommonJS会将path模块运行一遍,并返回一个对象,并将这个对象缓存起来,这个对象包含path这个模块的所有API。以后无论多少次加载这个模块都是取这个缓存的值,也就是第一次运行的结果,除非手动清除。
- ES6会从path模块只加载3个方法,其他不会加载,这就是编译时加载。ES6可以在编译时就完成模块加载,当ES6遇到import时,不会像CommonJS一样去执行模块,而是生成一个动态的只读引用,当真正需要的时候再到模块里去取值,所以ES6模块是动态引用,并且不会缓存值。
因为CommonJS模块输出的是值的拷贝,所以当模块内值变化时,不会影响到输出的值。基于Node做以下尝试:
//person.js
var age = 18;
module.exports ={
age: age,
addAge: function () {
age++;
}
}
//my_module
var person = require('./person.js');
console.log(person.age);
person.addAge();
console.log(person.age);
//输出结果
18
18
可以看到内部age的变化并不会影响person.age的值,这是因为person.age的值始终是第一次运行时的结果的拷贝。
再看ES6
//person.js
export let age = 18;
export function addAge(){
age++;
}
//my_module
import { age, addAge } from './person.js';
console.log(age);
addAge();
console.log(age);
//输出结果
18
19