Description
一、ES6模块体系简述
-
1、上一篇“ javascript模块化进程 ”中也说到:历史上,JavaScript 一直没有模块体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。ES6之前,社区制定了一些模块加载方案,最主要的有 CommonJS(服务器)和 AMD/CMD(浏览器)两种。
-
2、ES6 在语言标准的层面上,实现了模块功能,完全可以取代 CommonJS 和 AMD(CMD) 规范,成为浏览器和服务器通用的模块解决方案。
二、ES6模块
-
1、ES6 模块与CommonJS 、 AMD 模块区别
-
ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
-
CommonJS 和 AMD 模块,都只能在运行时确定模块依赖关系(运行时加载),因为只有运行时才能得到模块对应的对象(如,CommonJS 模块就是对象,输入时必须查找对象属性)。
-
ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
-
-
2、ES6 模块特性
-
一个模块就是一个独立的文件,其内部的所有变量,外部无法获取。
-
编译时加载或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。
-
ES6模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入,因此没法引用模块本身。
-
-
3、ES6模块构成的两个关键字
- export: 规定模块的对外接口
- import: 输入模块提供的功能
-
4、export关键字
-
A、输出变量、函数、类
// 直接输出
export const name = 'jackxu';
export const add = (x = 0, y = 0) => {
return x + y;
};
export class Hello {
sayHi() {
console.log('Hi~!');
}
}
// 统一输出
const name = 'jackxu';
const add = (x = 0, y = 0) => {
return x + y;
};
class Hello {
sayHi() {
console.log('Hi~!');
}
}
export { name, add, Hello }
- B、输出的变量就是原变量名,可以使用as关键字重命名
const name = 'jackxu';
const add = (x = 0, y = 0) => {
return x + y;
};
class Hello {
sayHi() {
console.log('Hi~!');
}
}
export {
name as ESName,
add as addTwo,
Hello as Hi
}
-
5、export使用注意事项
-
A、export规定模块的对外接口,必须与模块内部的变量建立一一对应的关系
// 错误写法
const add = (x = 0, y = 0) => {
return x + y;
};
export add;
export 123;
// 正确写法
const add = (x = 0, y = 0) => {
return x + y;
};
const A = 1;
export { add, A }
- B、export命令可以出现在模块的任何位置,但必须处于模块顶层
const fn = () => {
export const a = 'bar';
};
fn();
-
6、import关键字
-
A、加载模块提供的功能(输入模块提供的功能)
import { name, add, Hello } form '模块相对路径/模块绝对路径/模块文件名'
模块后缀
.js
可以省略,相对路径./
不能省略
模块文件名,由于不带路径,必须进行配置(如webpack+nodejs路径配置)
如加载先前export输出变量:
// 加载多个变量
import { name, add, Hello } form './class/test17';
// 加载单个变量
import { name } form './class/test17';
- B、模块的整体加载:用星号 * 指定一个对象,所有输出值都加载在这个对象上面
import * as filters form '模块相对路径/模块绝对路径/模块文件名'
如整体加载先前export输出变量:
import * as test form './class/test17';
模块整体加载所在的那个对象(如上面test),应该是可以静态分析的,所以不允许运行时改变。
如修改先前export输出的函数add,虽然不会报错,但不应这么操作。
import * as test from './class/test17';
test.cname = '李四'; // 不恰当写法
test.add = () => 666; // 不恰当写法
- C、import命令具有提升效果,会提升到整个模块的头部,首先执行。
如先执行add,在import输入export输出的变量add
console.log(add(2));
import { add } from './class/test17';
- D、import语句会执行所加载的模块,如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。
import '../../assets/styles/collect.css' // 仅仅执行模块,但是不输入任何值
- E、import是静态执行,所以不能使用表达式和变量(这些只有在运行时才能得到结果的语法结构)
如下使用变量和表达式的import操作都会报错:
import { 'n' + 'ame' } from './class/test17';
let module = './class/test17';
import { name } from module;
const a = 1;
a === 1 ? import { name } from './class/test17' : '';
- 7、export default关键字
export
输出的模块,import
加载的时,需要知道加载的变量名、函数名或类名,否则无法加载。而实际业务中,很可能不知道具体变量名,这时候就需要使用export default关键字。
- A、export default输出的模块,使用import加载的时候,变量名可以任意指定名字,但import后面不使用
{}
// export default输出
const name = 'jackxu';
const add = (x = 0, y = 0) => {
return x + y;
};
class Hello {
sayHi() {
console.log('Hi~!');
}
}
export default { name, add, Hello }
// import 输入
import test from './class/test17';
console.log(test.name);
console.log(test.add(3, 6));
B、export default也可输出非匿名函数,系统默认函数名在模块外部无效,加载的时候视同匿名函数加载
匿名函数:
// export default输出
export default (arr = []) => {
return arr.filter(item => item > 6);
}
// import 输入
import filterArr from './class/test17';
console.log(filterArr([1, 4, 6, 8, 9, 10]));
非匿名函数:
// export default输出
export default function filter_arr(arr = []) {
return arr.filter(item => item > 6);
}
// import 输入
import filterArr from './class/test17';
console.log(filterArr([1, 4, 6, 8, 9, 10]));
- C、export default用于指定模块的默认输出,一个模块只能有一个默认输出,因此export default命令只能使用一次
const _A = 123,
_B = (...arg) => new Map().set('arg', arg);
export default _A;
export default _B;
- D、export default本质: 输出一个名为default的变量或方法,然后系统允许为其任意取名
demo1:
// babel转码前
export default () => {
console.log('山穷水尽,柳暗花明');
}
// babel转码后
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function () {
console.log('山穷水尽,柳暗花明');
};
demo2:
// babel转码前
const name = 'jackxu';
const fn = () => 5;
export default { name, fn };
// babel转码后
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var name = 'jackxu';
var fn = function fn() {
return 5;
};
exports.default = { name: name, fn: fn };
- E、export default其实只是输出一个叫做default的变量,所以它后面不能跟变量声明语句。
错误写法:
export default const _B = 123;
正确写法:
const _B = 123;
export default _B;
// 对比export
export const _B = 123;
export default 66;
// 对比export
export 66; // 错误写法
主要参考资料: