模块化

124 阅读3分钟

模块化主要作用

作用:封装和隐藏私有实现细节,以及保证全局命名空间干净

常用形式:基于闭包

核心是沿用了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由于他的导入导出都是动态的难以预测的,因此没法做到。

参考

juejin.cn/post/707336…

zhuanlan.zhihu.com/p/43844419