模块化目的
- 解决命名冲突
- 提供复用性
- 提高代码可维护性
ES Module
export
默认导出:
export default Person
按需导出:
export { age, name, sex }
(推荐)// 导出变量 export const name = "蛙人" export const age = 24 // 导出函数也可以 export function fn() {} export const test = () => {}
// 如果有多个的话 const name = "skinner" const age = 33 export { name, age } ```
混合导出与导入
可以使用
export
和export default
同时使用并且互不影响,只需要在导入时地方注意,如果文件里有混合导入,则必须先导入默认导出的,在导入单个导入的值。//混合导出 export const name = "skinner" export const age = 33 export default { fn() {}, msg: "hello skinner" }
//混合导入,则该文件内用到混合导入,import语句必须先是默认导出,后面再是单个导出,顺序一定要正确否则报错。 // index,js export const name = "skinner" export const age = 24 export default { msg: "skinner" } import msg, { name, age } from './index.js' console.log(msg) ```
- import
默认导入:import Person from "person"
按需导入:
import { age, name, sex } from "person"
导入值的变化
export
导出的值是值的引用,并且内部有映射关系,这是export
关键字的作用。而且导入的值,不能进行修改也就是只读状态。// index.js export let num = 0; export function add() { ++ num } import { num, add } from "./index.js" console.log(num) // 0 add() console.log(num) // 1 num = 10 // 抛出错误
Es Module是静态
if (true) { import xxx from 'XXX' // 报错 }
CommonJS
- CommonJS:用于服务器(动态化依赖)
- AMD:用于浏览器(动态化依赖)
- CMD:用于浏览器(动态化依赖)
- ES6 module
CommonJS
注意:浏览器不识别CommonJS语法,因此需要采用browser 打包处理
语法:
module.exports = value | exports.xxx = value
//a.js //方式1: //注意!!:向外暴露的是exports对象,原始exports是{} module.exports = { a: 1 } //方式2 exports.a = 1
// b.js var module = require('./a.js') module.a // -> log 1
先说b.js中的require,其实就是包装了一层立即执行函数,避免污染全局变量
再说a.js,首先我们需要知道module是怎么实现的,如下。module中有一个特定id,还有一个exports属性
// module 基本实现 var module = { id: 'xxxx', // 我总得知道怎么去找到他吧 exports: {} // exports 就是个空对象 }
为什么CommonJS有两个语法,原因如下:
// 这个是为什么 exports 和 module.exports 用法相似的原因 var exports = module.exports
注意:
虽然 exports 和 module.exports 用法相似,但是不能对 exports 直接赋值。因为 var exports = module.exports 这句代码表明了 exports 和 module.exports 享有相同地址,通过改变对象的属性值会对两者都起效,但是如果直接对 exports 赋值就会导致两者不再指向同一个内存地址,修改并不会对 module.exports 起效。再说require执行的是什么函数
//require执行load函数 var load = function (module) { // 导出的东西 var a = 1 module.exports = a return module.exports }; // 然后当我 require 的时候去找到独特的 // id,然后将要使用的东西用立即执行函数包装下
特点
不支持重复导入
let data = require("./index.js") let data = require("./index.js") // 不会在执行了
动态导入
CommonJs
支持动态导入,什么意思呢,就是可以在语句中,使用require
语法,来看如下案例。let lists = ["./index.js", "./config.js"] lists.forEach((url) => require(url)) // 动态导入 if (lists.length) { require(lists[0]) // 动态导入 }
导入值是拷贝值
CommonJs
导入的值是拷贝的,所以可以修改拷贝值,但这会引起变量污染,一不小心就重名。// index.js let num = 0; module.exports = { num, add() { ++ num } } let { num, add } = require("./index.js") console.log(num) // 0 add() console.log(num) // 0 num = 10
上面example中,可以看到
exports
导出的值是值的拷贝,更改完++ num
值没有发生变化,并且导入的num
的值我们也可以进行修改
CommonJs和Es Module的区别
CommonJs
- CommonJs可以动态加载语句,运行时
- CommonJs混合导出,还是一种语法
- CommonJs导出值是拷贝,可以修改导出的值,这在代码出错时,不好排查引起变量污染
Es Module
- Es Module是静态的,不可以动态加载语句,编译时
- Es Module混合导出,单个导出,默认导出,完全互不影响
- Es Module导出是引用值之前都存在映射关系,并且值都是可读的,不能修改