esmodule与commonjs静态加载与动态加载


本文围绕js模块化介绍 commonjs 、 esmodule 和静态加载与动态加载。

1. 模块化

早期 JavaScript 开发很容易存在全局污染和依赖管理混乱问题。模块化就是把各个功能拆解成各个模块。而规范就有 commonjs 和esmodule ,我们把每一个js文件称之为模块。

1.1 避免污染全局变量

没有模块化,那么 script 内部的变量是可以相互污染的。比如有一种场景,有./index.js 文件和 ./list.js 文件为 功能A 开发的,./home.js 为 功能B 开发的。他们都有name变量,就会造成变量污染,可能达不到相应的预期。

1.2 依赖管理

依赖管理也是一个难以处理的问题。正常情况下,执行 js 的先后顺序就是 script 标签排列的前后顺序。那么如何三个 js 之间有依赖关系,那么应该如何处理呢?如果加载三个js未免太过紊乱,那么就需要模块化。

2. Commonjs的基本使用

commonjs 的提出,弥补 Javascript 对于模块化,没有统一标准的缺陷。nodejs 借鉴了 commonjs 的 Module ,实现了良好的模块化管理。

2.1 导出

CommonJs使用 module.exports 导出, 但有 对象属性 两种写法。

// 导出一个对象
module.exports = {
    name: "z",
    age: 24,
    sex: "male"
}

// 导出某个属性
module.exports.name = "z"
module.exports.sex = null
module.exports.age = undefined

2.2 直接导出

导出也可以省略module关键字

exports.name = ""
exports.sex = "male"

2.3 导入

CommonJs中使用require语法可以导入 整个对象,如果想要单个的值,可以通过 解构 对象来获取。

let data = require("./index.js")
console.log(data) // { name: "z", age: 24 }
//index.js
module.exports.name = "z"
module.exports.age = 24

2.4 动态导入

CommonJs支持动态导入,指的就是运行中加载,那么我们使用require语法就有如下写法:

let lists = ["./index.js", "./config.js"]
lists.forEach((url) => require(url)) // 动态导入

if (lists.length) {
    require(lists[0]) // 动态导入
}

2.5 导入的值是拷贝的

let { num, add } = require("./index.js")
num = 10//修改对其它引用不造成影响
//index.js
module.exports = {
    num:0,
    add() {
       ++ this.num 
    }
}

3. ES Module

es6提出了ESModule。

3.1 导出

语法上 ESModule 有两种导出,体现在关键字上,单个导出(export)、默认导出(export default)。单个导出在导入时不像CommonJs一样直接把值全部导入进来了,默认导出就是全部直接导入进来,当然Es Module中也可以导出任意类型的值。

// 单个导出
export const name = "z"
export const age = 24

// 默认导出
export default {
    fn() {},
    msg: "z"
}

3.2 导入

(1)单个导入,使用import…from语法带花括号{} ,注意不是解构只是语法相似

import { name, age } from './index.js';
import { name as zname, age as zage} from './index.js';//重命名
import * as idx from './index.js';//如果想合并所有单个就这么写
console.log(name, age) // "z" 24
// index.js
export const name = "z"
export const age = 24

(2)默认导入需要重命名

// 匿名导出的,要重命名
import getName from './index.js';
// index.js
const Programmer = {name: 'z',age:24}
export default Programmer

3.3 混合导入 (注意)

//那么先导msg
import msg, { name, age } from './index.js'
console.log(msg) // { msg: "z" }
//如果导出同时用了export default 和 export
export const name = "z"
export const age = 24
export default {
    msg: "z"
}

3.4 导入的值是引用地址

export导出的值是值的引用,而且导入的值,不能进行修改也就是只读状态。

import { num, add } from "./index.js"
console.log(num) // 0
add()
console.log(num) // 1
num = 10 // 抛出错误
//index.js
export let num = 0;
export function add() {
    ++ num
}

3.5 Es Module静态分析

就是Es Module语句 import只能声明在该文件的最顶部,不能动态加载语句,Es Module 语句运行在代码编译时。

if (true) {
	import xxx from 'XXX' // 报错
}

4. 缓存

不管是CommonJs还是Es Module都不会重复导入,就是只要该文件内加载过一次这个文件了,再次导入一次是不会生效的。

5. 总结

commonjs是动态加载,同步执行;esmodule是静态分析,动态引入(esmodule也可以动态导入,在es2020增加基于 promise 的 import() 函数)

commonjs的导出方式是 有属性和对象写法的 module.exports(可省略module);esmodule的导入方式是 export 和 export default

commonjs的导入方式是 require();esmodule的导入方式是 import…from;


文章作者: iamfugui
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 iamfugui !
评论
  目录