js - 模块化

一、概念

模块化是指解决一个复杂问题时,自顶向下逐层把系统划分为若干模块的过程,模块是可组合、分解和更换的单元。

编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块。

1. 模块化的好处

  • 提高了代码的 复用性
  • 提高了代码的 可维护性
  • 可以实现 按需加载

2. 模块化规范产品

es6 之前的模块化规范有:

规范实现产品
CommonJSNodeJS、Browserify
AMDrequireJS
CMDseaJS

二、ES6 模块化

想要使用 es6 的模块化,则必须申明 <script type="module"></script> 标签的 type 属性值为 module

<script type="module" src="../xxx.js"></script>

1. 暴露语法汇总

1.1. 默认暴露

一个文件中只可以有一个默认暴露

// m1.js
export default {
  SUCCESS: 0,
  
  getCodeMessage() {
  	console.log('默认暴露')
	}
}
1.2. 分别暴露

在申明的 变量方法 前增加关键字 export

// m2.js
export const SUCCESS = 0

export function getCodeMessage() {
  console.log('分别暴露')
}
1.3. 统一暴露
// m3.js
const SUCCESS = 0

function getCodeMessage() {
  console.log('统一暴露')
}

export {
  SUCCESS, // SUCCESS: SUCCESS
  getCodeMessage // getCodeMessage: getCodeMessage
}

2. 引入语法汇总

2.1. 通用引入

不管使用什么方式向外暴露,都可以使用 通用引入

<script type="module">
  // 默认暴露
  import * as m1 from './modules/m1.js'
  // 分别暴露
  import * as m2 from './modules/m2.js' 
  // 统一暴露
  import * as m3 from './modules/m3.js' 

  m1.default.getCodeMessage()
  m2.getCodeMessage()
  m3.getCodeMessage()
</script>
  • 使用该种方式导入 默认暴露 的模块,前面必须得加 default 才行
  • 可以看到,对于 分别暴露统一暴露 的模块,导入时的用法使用一致
2.2. 解构赋值形式
<script type="module">
  // 默认暴露(因为 default 是关键字,所以必须得起别名)
  import {default as m1} from './modules/m1.js'
  // 分别暴露
  import {SUCCESS, getCodeMessage} from './modules/m2.js' 
  // 统一暴露(因为变量不能重复,可以使用别名)
  import {SUCCESS as a, getCodeMessage as fn} from './modules/m3.js' 

  m1.getCodeMessage()
  getCodeMessage()
  fn()
</script>
2.3. 简便形式

只能针对 默认暴露 使用

<script type="module">
  // 默认暴露
  import m1 from './modules/m1.js'

	m1.getCodeMessage()
</script>

3. 其他说明

  • 分别暴露统一暴露 更推荐使用 统一暴露,因为这样就可以在脚本尾部,一眼看清楚输出了哪些变量

  • import 命令具有提升效果,会提升到整个模块的头部先执行

    foo();
    import { foo } from './my_module.js';
    

    上面的代码不会报错,因为 import 的执行早于 foo 的调用。这种行为的本质是,import命令是编译阶段执行的,在代码运行之前

  • import 是静态执行,所以不能使用表达式和变量,以下代码会报错

    // 报错
    import { 'f' + 'oo' } from './my_module.js';
    
    // 报错
    let module = './my_module.js';
    import { foo } from module;
    
    // 报错
    if (x === 1) {
      import { foo } from './module1.js';
    } else {
      import { foo } from './module2.js';
    }
    
  • 如果多次重复执行同一句 import 语句,那么只会执行一次,而不会执行多次

    import './lodash.js';
    import './lodash.js';
    
  • 顶层 thisundefined

三、CommonJS 模块化

1. 概念

  • 每个模块内部,module 变量代表当前模块
  • module 变量是一个对象,module.exports 是对外的接口
  • 加载某个模块即加载该模块的 module.exports 属性
  • 在服务端:模块的加载是 同步
  • 在浏览器端:模块需要提前编译打包处理(需要用到 browserify

2. module.exports 导出

  • 在自定义模块中,可以使用 module.exports 对象,将模块内的成员共享出去,供外界使用。
  • 外界用 require() 方法导入自定义模块时,得到的就是 module.exports 所指向的对象。
// 向 module.exports 对象上挂载属性
module.exports.username = 'admin'
// 向 module.exports 对象上挂载方法
module.exports.getUserInfo = () => {}

3. exports 导出

由于 module.exports 单词写起来比较复杂,为了简化向外共享成员的代码,Node 提供了 exports 对象。默认情况 下,exportsmodule.exports 指向同一个对象

使用 require() 方法导入模块时,导入的结果,永远以 module.exports 指向的对象为准。

/* 案例一 */

exports.a = 1
module.exports = {
  b: 2
}
// 最终导出的结果为 { b: 2 }
/* 案例二 */

module.exports.a = 1
exports = {
  b: 2,
  c: 3
}
// 最终导出的结果为 { a: 1 } 
/* 案例三 */

module.exports.a = 1
exports.b = {
  id: 10
}
// 最终导出的结果为 { a: 1, b: { id: 10 } } 

4. require 引入

  • 内置模块或第三发模块:xxx 指的是包名
  • 自定义模块:xxx 指的是模块的路径

5. 其他说明

  • 对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值
  • 对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
  • 当使用require命令加载某个模块时,就会运行整个模块的代码。(执行时运行)
  • 当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
  • 循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。
  • 顶层 this 指向所在模块

四、browserify

让服务器端的 CommonJS 格式的模块可以运行在浏览器端。

1. 安装

全局和局部必须都安装才能使用

  • 全局:npm install browserify -g
  • 局部:npm install browserify --save-dev

2. 运行

# 格式说明:browserify 要执行的文件路径 -o 编译后放置的文件路径
browserify src/app.js -o dist/budle.js
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值