JS中的模块化

预计阅读时间: 5 分钟

模块化

"模块化开发的目的

模块化开发目的是,把程序划分成一个个单独的有自己的逻辑代码作用域不会相互影响的代码文件,既可以按需暴露自己的变量、函数、对象给其他的模块使用,又可以通过某种方式导入其他模块的变量、函数、对象

总结:

模块就是,有独立作用域,可以导出导入变量和函数的单独结构,目的是降低代码复杂度,方便管理

JS中模块化的方式

1. CommonJS

"CommonJS的特点

CommonJS是一个规范,在node.js和浏览器里均有实现,简称CJS。

  • node中默认使用
  • 在浏览器里需要由第三方库Browserify实现
  • webpack具备对commonjs的实现
"CommonJS的特点

CommonJS是一个同步的模块化方案,在浏览器中使用时,会阻塞页面加载,导致页面失去响应

规范内容

1.关键词

  • 使用exports/module.exports关键词实现导出
  • 使用require函数实现导入

2. 导出和导入的过程

  1. 往模块中的module.exports/exports对象上添加属性,实现模块导出
  2. 导入的地方使用require函数,获得上述模块的module.exports对象内存地址引用,便能读取使用到模块导出的变量或函数
"CommonJS的注意点
  1. 模块exports是一个空对象
  2. 模块中的module是一个对象,并且有一个exports属性,内存指向了模块中的exports对象,所以初始化时,module.exportsexports是同一个内存引用,往两者上添加的属性是等价的
  3. 当修改module.exports指向一个新的对象时,module.exportsexports就不再是同一个内存引用,exports添加的属性不会被导出
  4. 也就是实际上导出的是module.exports的指向的对象,而不是exports
  5. require读取到的是module.exports的内存地址,这意味着在导入的地方可以直接修改模块中的属性
  6. 但是规范要求,不要这么做,因为这样会导致模块中的属性被污染
main
foo模块
bar模块
main.cjs
1const foo =require('./foo')
2const bar = require('./bar')
3
4
5console.log('main 模块 bar.name bar.age', bar.name, bar.age)  // undefined 20
6console.log('main 模块 1 foo.name foo.age', foo.name, foo.age) // foo 18
7setTimeout(()=>{
8  // 1000ms后,在bar模块中修改foo模块的name属性,main模块中也同步修改后的name属性
9  console.log('main 模块 2 foo.name foo.age', foo.name, foo.age) // bar 18
10},2000)

3. CommonJS的内存图

2. ESModule

"ESModule的特点

ES6引入js原生的模块化方案,使用importexport 关键词,实现模块隔离

CommonJS的区别:

  • 模块外不能直接修改模块内变量,否则会抛出错误
  • 实现了静态分析

2.1.Export 导出声明

"导出声明不受暂时性死区规则的限制

你可以在声明变量 X 之前,声明当前模块导出 X。

导出类型
  • 默认导出
默认导出
1// export default value/func/name 值/函数名/变量名
2export default 1
3export default function(){}
4function foo(){}
5export default foo
6
7// 默认导出声明
8export default expression;
9export default function functionName() { /* … */ }
10export default class ClassName { /* … */ }
11export default function* generatorFunctionName() { /* … */ }
12export default function () { /* … */ }
13export default class { /* … */ }
14export default function* () { /* … */ }
  • 分别导出
export
1// 2. 分别导出
2// export const/let/const // 单独去在定义时导出
3const abc = 0
4export { abc } // 最后统一导出
5export { abc as default } // 分别导出重命名
"分别导出重命名
  1. defualt是一个关键词,上面这样写与 export default 相同
  2. export {} 是一个语句,后面的花括号并不是一个对象,是用花括号括起来的用逗号分割的列表,不能使用对象增强语法 ,只能使用as重命名
  • 导出声明
导出声明
1export let name1, name2/*, … */; // also var
2export const name1 = 1, name2 = 2/*, … */; // also var, let
3export function functionName() { /* … */ }
4export class ClassName { /* … */ }
5export function* generatorFunctionName() { /* … */ }
6export const { name1, name2: bar } = o;
7export const [ name1, name2 ] = array;
  • 导出列表
导出列表
1export { name1, /* …, */ nameN }; //是用花括号括起来的用逗号分割的列表
2export { variable1 as name1, variable2 as name2, /* …, */ nameN }; // 重命名
3export { variable1 as "string name" }; // 重命名
4export { name1 as default /*, … */ }; // 默认导出

2.2 Import 导入声明

Import
1//1. 导入默认模块
2import xxx from './xxx'
3//2. 导入分别导出
4import { abc,cbd } from './xxx'
5//3. 一起结合
6import * as aModule from './xxx' //方式一
7import { default as aModule,abc ,cbd } from './xxx' // 方式二
8import aModule,{ abc ,cbd } from './xxx' //方式三
9
10
11// 官方例子
12import defaultExport from "module-name";
13import * as name from "module-name";
14import { export1 } from "module-name";
15import { export1 as alias1 } from "module-name";
16import { default as alias } from "module-name";
17import { export1, export2 } from "module-name";
18import { export1, export2 as alias2, /* … */ } from "module-name";
19import { "string name" as alias } from "module-name";
20import defaultExport, { export1, /* … */ } from "module-name";
21import defaultExport, * as name from "module-name";
22import "module-name"; //副作用导入,只是为了执行一个模块内的代码
23
24// 导入类型
25import type { T } from 'xxx'
26import  { type T  } from 'xxx'

2.3 结合简化

结合简化
1export * from "x.js";
2export { name } from "x.js";
3export { defualt as name, nameb } from "x.js";
4
5// 导出模块合集
6export * from "module-name";
7export * as name1 from "module-name";
8export { name1, /* …, */ nameN } from "module-name";
9export { import1 as name1, import2 as name2, /* …, */ nameN } from "module-name";
10export { default, /* …, */ } from "module-name";
11export { default as name1 } from "module-name";

2.4 动态导入

动态导入
1import("/modules/mymodule.js").then((module) => {
2  // Do something with the module.
3});

Import

按MDN的说法并不是一个函数,而是类函数的方式调用,它是一个关键词

MDN- import

import