1.简介
Module是ES6模块化思想,他 的设计思想是尽量的静态化,使得编译时就确定模块的依赖关系,以及输入和输出的变量。
ES6模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入
import { stat,exists,readFile} from 'fs';
上面代码的实质是从fs模块加载3个方法,其他方法不会加载。这种加载称为编译时加载或者静态加载,效率比commonjs模块的加载方式高。
es模块的好处
(1).不再需要UMD模块格式了,将来服务器和浏览器都会支持ES6模块格式,目前,通过各种工具库,已经做到了这一点
(2).将来浏览器的新API就能用模块格式提供,不再需要做成全局变量或者navigator对象的属性
(3).不再需要对象作为命名空间,未来这些功能可以通过模块提供。
2.严格模式
ES6的模块自动采用严格模式,不管你有没有在头部加“use strict”
严格模式限制
(1)变量必须先声明或使用
(2)函数的参数不能有同名属性
(3)不能使用with语句
(4)不能对只读属性赋值
(5)不能删除不可删除的属性
(6)禁止使用this指向全局对象
(7)增加了保留字(protected,static,interface)
3.export命令
模块的功能主要由两个命令构成:export和import
export命令用于规定模块对外的接口,import用于输入其他模块提供的功能
任何一个模块都是独立的文件,外界无法获取内部定义的变量或方法,必须通过export关键字输入该变量或者方法
例如:
export var firstName = "michael";
exprot var year = "2018";
或者用对象的方式输出:
var firstName = "michael";
var year = 2018;
export {firstName,year};
export命令可以输出函数或者类
export function multiply(x,y){
return x*y;
}
用as关键字重命名
function a(){...}
function b(){...}
export {
a as newNameA,
b as newNameB,
b as newNameB2//此处b可以用不同的名字输出两次
}
export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部的实时的值。
export var foo = "bar";
setTimeout(() => foo = "baz",500);
上面代码输出变量foo,值为bar,500毫秒后变成baz,这与commonjs不同,commonjs模块输出的值是缓存
export命令可以出现在模块最外层作用域的任何地方
4.import命令
使用export命令定义了模块的对外接口之后,其他js文件就可以通过import命令加载这个模块
//main.js
import {firstName,lastName,year} from "./profile.js";
function setName(element){
element.textContent = firstName + '' + lastName;
}
import 也可以为引入的变量重新去名字,使用as关键字,同export相同
import命令输入的变量都是只读的,不可更改,如果为对象,改写属性是可以的,建议不要轻易改写
由于import是静态执行,即编译前执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构
5.模块的整体加载
//circle.js
export function area(radius){
return Math.PI * radius * radius
}
export function circumference(radius){
return 2 * Math.PI *radius;
}
正常加载模块:
//main.js
import {area,circumference} from './circle';
console.log("圆面积" + area(5));
整体加载模块:
import * as circle from './circle';
console.log('圆面积'+circle.area(5));
注意:整体加载的对象circle是静态分析,不允许运行时改变
6.export default命令
使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载,export default 命令为模块指定默认输出;
export default function () {
console.log("default");
}//默认输出一个函数
其他模块加载该模块时,import命令可以为该匿名函数指定任意名字
import customName from './sdfasdf';//不用使用大括号
customName();
export default也可以输出非匿名函数,但被视为匿名函数,引入时也可以任意命名
export default命令用于指定模块的默认输出,因此只能用一次,export default命令的本质是将后面的值赋值给default变量
7.export和import的复合写法
如果在一个模块中,先输入后输出同一个模块,import语句可以与export语句写在一起
export { foo, bar} from 'my_module';
//等同于
import { foo, bar} from 'my_module';
export { foo, bar}
需要注意的是,写成一行以后,foo和bar实际上并没有被导入当前模块,只是相当于对外转发的这两个接口,导致当前模块不能直接使用foo和bar
8.模块的继承
9.跨模块常亮设置跨模块常量或者说一个值要被多个模块共享,可以采用下面的写法
//constants.js 模块
export const A = 1;
export const B = 2;
export const C = 3;
//test1.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);//1
console.log(B);//2
但是如果使用的变量非常多,可以建一个专门的constants目录,将各种常量写在不同的文件里面,保存在该目录下
//constants/db.js
export const db = {
url:"",
admin_username:"admin",
admin_password:"admin password"
};
//constants/user.js
export const users = ['root', 'admin','staff']
将这些文件输出的常量,合并在index.js里面
//constants/index.js
export {db} from './db';
export {users} from './users';
使用的时候,直接加载index.js即可
//script.js
import {db,users} from './index'
10.import()
import会被javascript引擎静态解析,先于模块其他语句执行,所以不能用在语句中,必须放在顶层作用域中,虽然这样效率较高,但是无法在运行时加载,语法上,条件加载就不可以实现,因此引入import()函数,完成动态加载
import(aaa);其中参数aaa,指要加载的模块的位置
import()返回一个Promise对象
const main = document.querySelector("main");
import('./section-module')
.then(module => {
module.loadPageInfo(main);
})
.catch(err => {
main.textContent = err.message;
})
适用场合
(1)按需加载
import()可以在需要的时候,再加载某个模块
button.addEventListener('click',event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
})
})
监听事件,用户点击才会加载这个模块
(2)条件加载
import()放在if代码块,根据情况加载不同的模块
if(condition){
import('moduleA').then(...)
}else{
import('moduleB').then(...)
}
(3)动态模块路径
import(f()).then(...)根据函数f()返回的结果,加载不同的模块