跳到主要内容

JavaScript模块化

什么是模块化?

将项目划分成一个个小的结构,每个结构里面都有着自己的变量,函数,不会影响到其他模块使用,可以自定义导出模块中的变量函数等,其他模块也可以引入导出的变量函数等.

没有模块话会导致 比如命名冲突的问题.

AMD 规范

requirejs 为全局添加了 define 函数,你只要按照这种约定的方式书写这个模块即可。

这里的约定方式就指的是 AMD 规范.

AMD 规范的内容,其主要内容就是定义了 define 函数该如何书写,只要你按照这个规范书写模块和依赖,require.js 就能正确的进行解析。

CMD 规范

与 AMD 一样,CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。

CMD 规范的内容,主要内容就是描述该如何定义模块,如何引入模块,如何导出模块,只要你按照这个规范书写代码,sea.js 就能正确的进行解析。

AMD 和 CMD 规范已经使用的很少了,这里简单说下

CommonJS

CommonJS 规范大多用于服务器端比如 node.

// 导出
const add = function (x, y) {
return x + y
}

module.exports.add = add

// 导入
const add = require('./add.js')
console.log(add.add(1, 1))
  • CommonJS 规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。
  • 服务端一般文件存于本地硬盘,所以加载起来比较快.
  • 在浏览器中通常不使用 CommonJS,现在浏览器已经支持 ES Modules,另一方面借助于 webpack 等工具可以实现对 CommonJS 转换. Module 代码的转换;

ES Modules

ECMAScript2015 规定了新的模块加载方案。

const firstName = 'Michael'
const lastName = 'Jackson'
const year = 1958
// 导出
export { firstName, lastName, year }
// 导入
import { firstName, lastName, year } from './profile'

ES6 与 CommonJS

它们有两个重大差异。

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。 ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令 import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的 import 有点像 Unix 系统的“符号连接”,原始值变了,import 加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。 因为 CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
// 输出模块 counter.js
let counter = 3

function incCounter() {
counter++
}
module.exports = {
counter,
incCounter: incCounter,
}

// 引入模块 main.js
const mod = require('./counter.js')

console.log(mod.counter) // 3
mod.incCounter()
console.log(mod.counter) // 3

将 counter 为一个引用类型的话:

// 输出模块 counter.js
const counter = {
value: 3,
}

function incCounter() {
counter.value++
}
module.exports = {
counter: counter,
incCounter: incCounter,
}
// 引入模块 main.js
const mod = require('./counter.js')

console.log(mod.counter.value) // 3
mod.incCounter()
console.log(mod.counter.value) // 4

发现 value 是会发生变化的,针对引用类型也可以说是值的引用

改成 ES6

// counter.js
export let counter = 3
export function incCounter() {
counter++
}

// main.js
import { counter, incCounter } from './counter'
console.log(counter) // 3
incCounter()
console.log(counter) // 4

参考

https://github.com/mqyqingfeng/Blog/issues/108