前端模块化是前端工程化的基石,符合按模块开发的流程,代码耦合度低,复用率高。模块化思想就是隔离不同的js文件,暴露当前模块中的对象、方法等供其他模块使用,其实就是将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起。模块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信。
模块化的好处:
在学习ES6的模块化之前先了解一下之前出现的模块化,比较常用的有三种规范定义:CommonJS、AMD、CMD。
AMD (Asynchronous Module Definition) 就是异步加载模块,多用于浏览器端。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。此外AMD规范比CommonJS规范在浏览器端实现要来着早。
CMD规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。CMD规范整合了CommonJS和AMD规范的特点。
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
在ES6模块中自动采用严格模式。规定:
with
delete
不可删除属性直接报错delete prop
、只能删除属性delete global[prop]
eval
不会再外层作用域引入变量eval
和arguments
不可重新赋值arguments
不会自动反应函数参数变化this
指向全局注意:在ES6模块中,顶层this
为undefined
,不应该被使用。
分别暴露的意思就是,一个一个地将模块中的对象、方法、变量等暴露。示例如下,module1.js:
//暴露一个变量
export let a = 100;
//暴露一个对象
export const car = {
brand: "奥迪",
color: "黑色"
}
//暴露一个函数
export function add(a, b) {
return a + b;
}
在demo1.js中引入并使用:
import { a, car, add } from './module1'
//import {a as a1,car,add} from './module1' //当多个模块中有重名的情况时,可以使用别名
console.log(a);
console.log(car);
console.log(add(1, 2));
统一暴露,就是先写好变量、对象、方法等,最后使用export {...}语句暴露,示例如下:
let a = 100;
let car = {
brand: "奥迪",
color: "黑色"
}
function add(a, b) {
return a + b;
}
//简写形式
export {
a,
car,
add
}
//完整形式
/* export {
a as a1,
car as car1,
add as add1
} */
在demo2.js中引入并使用:
import { a, car, add } from './module2' //和前面的分别暴露引入的方式一致
console.log(a);
console.log(car);
console.log(add(1, 2));
默认暴露只能暴露一次。
//注意默认暴露一个文件中只能默认暴露一次
//module3.js文件。暴露一个对象
export default {
name:"张三",
age:18
}
//module4.js。暴露一个函数
export default function add(a,b){
return a+b;
}
在demo3.js中引入并使用:
import student from './module3'
import add from './module4'
console.log(student);
console.log(add(1,2));
就是同时在一个文件中同时使用以上提到的3中暴露方式,实例如下,module5.js:
//分别暴露
export const add = (a, b) => {
return a + b;
}
//统一暴露
let a = 100;
let car = {
brand: "奥迪",
color: "黑色"
}
export {
a,
car
}
//默认暴露
export default sub = (a, b) => a - b;
在demo4.js中引入并使用:
//引入多种暴露模式的模块
import module5, { add, a, car } from './module5'
console.log(module5(2, 1));
console.log(add(1, 1));
console.log(a);
console.log(car);
最后注意事项:
export语句输出的接口是对应值的引用,也就是一种动态绑定关系,通过该接口可以获取模块内部实时的值。
对比CommonJS规范:CommonJS模块输出的是值的缓存,不存在动态更新。
export命令规定要处于模块顶层,一旦出现在块级作用域内,就会报错,import同理。