模块化主要作用
作用:封装和隐藏私有实现细节,以及保证全局命名空间干净
常用形式:基于闭包
核心是沿用了node的require()函数,基于require()的模块化是node编程环境的基础
ES6使用import和export关键字定义了自己的模块化
基于类 对象 闭包的模块
类的一个重要特征是自己充当了自己方法的模块。类之所以成为模块,是因为对象是模块。
但类和对象作为模块的问题是:类和对象没有提供任何方式来隐藏模块内部的实现细节。
因此要用闭包,来隐藏内部细节,然后返回一个对象比如返回一个类,返回一个值,或返回一个对象来暴露多个值。
webpack基本原理:解析代码文件,把每个文件的内容包装在一个立即调用的函数表达式中,还可以跟踪每个函数的返回值,并将所有文件拼接为一个大文件
code
node中的模块
每个文件都是一个拥有私有命名空间的独立模块
用法:
导入node内置模块或安装的模块,或从绝对路径或相对路径
const t1=require("fs")
// 导入整个模块对象
const t2=require("../utils.js").test(data)
// 导入特定属性
const {t3}=require('')
// 通过解构导入特定属性
导出对象或类或变量或函数等:
module.exports= xx
// 一个模块只有一个
或
exports.xx= ...
// 可以有多个
ES6中的模块
模块与普通js脚本的区别:
模块中的代码自动应用严格模式;并且即使顶级代码中this也是undefined
原生方式使用:
<script type="module"></script>
导出对象或类或变量或函数等:
只能出现在js代码的顶层,不能在类、函数、循环、条件内部导出。 模块导出的值每次运行都相同。
export xx
或
export {xx, xxx, xxxx}
// 并不是对象字面量,只是花括号语法
或
export default xxx
// 一个模块只能有一个,可以导出一个对象字面量
// export default和export 通常不一起用,但也可以出现在同一个模块里
export {
xx as myXX,
xxx as myXXX
}
// 注意xx和xxx是标识符不能是表达式
导入:
用法
import xx from 'xx.js'
import * as xx from 'xx.js'
import {xx, xxx} from 'xx.js'
import {xx as myXX, xxx} from 'xx.js'
import { default as myXX, xxx} from 'xx.js'
import 'xx.js'
// 可以用于导入没有导出的模块,会在被首次导入时运行一次
同导出,只能出现在js代码的顶层,不能在类、函数、循环、条件内部导出。
与函数声明类似,会被“提升”到顶部。
动态导入
import("xx.js").then((res)=>{
//
})
或
async myTest(){
const myXX=await import('xx.js')
//
}
其他
import.meta.url 加载模块时使用的路径
script标签中使用 // 待补充
对比
ES6的Module属于编译时加载,即静态加载,在编译时就能够确定模块的依赖关系,以及输入和输出的变量;CommonJS属于运行时加载,都只有在代码运行时才能确定这些东西。例如:
if(isTrue){
module = require("./a")
}else{
module = require("./b")
}
ESM可以做到tree shaking,按需加载。而CommonJs由于他的导入导出都是动态的难以预测的,因此没法做到。
参考