【webpack学习笔记—3】ES6 Module和CommonJS的3点对比

1. 前言

在开始阅读本文前,建议先阅读下面的两篇文章:

  • 【webpack学习笔记—1】3点弄懂CommonJS模块打包标准
  • 【webpack学习笔记—2】ES6模块打包标准

2. 依赖关系的动态与静态

CommonJS是==动态的==: 模块间的依赖关系是在代码运行阶段确定的
ES6 Module是==静态的==: 模块间的依赖关系是在代码编译阶段确定的

二者的这一点不同,显示出的ES6 Module的优点如下:

  • ES6 Module在编译阶段就能确定出模块间的依赖关系,可以排除掉未引用的模块,减小打包资源的体积
  • 静态结构可以保证模块间值传递的类型正确(因为在编译阶段就会检查)
  • CommonJS本质是导入module对象,而ES6 Module导入的是只读变量,减少层级引用编译,效率更高

3. 模块导入的不同

CommonJS导入的模块是原来模块的拷贝,任何操作都不会对原拷贝有影响;而ES6 Module导入的模块是原来模块的只读引用,虽然是只读引用,但是依然可以设计出通过函数方法对原模块的改变:

// Sam.js
export default {
    name : 'sam',
    age : 25, 
    getAge: function() {
        return this.age++
    }
}

// index.js
import Sam from "./Sam.js";
for (let i = 0; i < 3; i++) {
  console.log(Sam.getAge());
}
// 控制台输出
// 25
// 26
// 27

需要注意的是,用ES6 Module导出的变量不可以直接修改,否则会抛出只读错误。

import count from './calculator' // 假设count是被导出导入的一个数字
// count++ // SyntaxError: "count" is read-only

4. 循环引用

这部分我理解还不够深刻,只是简单地记住概念,暂时先做部分记录,欢迎交流
如果使用CommonJS,模块间的循环引用会出现空值,因为它是脚本式地执行下去,如果执行到某一行当时的值未定义,就会获取到类似空的对象等(因为webpack有做判断为空时创建一个空对象{});
而ES6 Module则会在编译时先把各个模块间关系先生成,再声明对应的变量和函数方法等,利用这个特点,可以跟上一节一样,创建出可以循环引用且不为空的结果,方式参考第三点中的方式,其中CommonJS也可以通过如下方式实现引用:
下面来展示第一种情况,当循环引用时,如果使用CommonJS会怎么样:

// index.js
1 > require('./A.js')

// A.js
2 > const B = require('./B.js')
3 > console.log('value of B: ', B)
4 > module.exports = 'This is A !'

// B.js
5 > const A = require('./A.js')
6 > console.log('value of A:', A)
7 > module.exports = 'This is B !'

// 控制台
// value of A:  {}
// value of B:  this is B !
  • 首先会执行第1行index.js中的代码,然后跳转到A.js中执行2的代码,再跳转到B.js中执行5的代码
  • 此时不会再跳回A,而是往下执行6、7的代码。因为是动态执行,此时还没读到4,所以此时的A会因为webpack的处理,被赋予{},依旧是打印内容为空的对象。
  • 执行完6、 7,B.js中的代码执行完毕,回到A.js中,执行3,因为B.js的导出已经被度去过,所以打印了出来,然后再执行4导出文本,代码执行完毕。

内容均为我个人阅读《Webpack实战:入门、进阶与调优》后的回忆总结,这是一本很不错的书,想深入了解webpack的同学可以去看看这本书

你可能感兴趣的:(【webpack学习笔记—3】ES6 Module和CommonJS的3点对比)