AboutFE icon indicating copy to clipboard operation
AboutFE copied to clipboard

50、模块化发展历程、IIFE、AMD、CMD、CommonJS、UMD、ES Modules

Open CodingMeUp opened this issue 4 years ago • 2 comments

CodingMeUp avatar Jun 23 '20 15:06 CodingMeUp

模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。

IIFE: 使用自执行函数来编写模块化,特点:在一个单独的函数作用域中执行代码,避免变量冲突

(function(){
  return {
	data:[]
  }
})()

AMD: 使用requireJS 来编写模块化,特点:依赖必须提前声明好

define('./index.js',function(code){
	// code 就是index.js 返回的内容
})

CMD: 使用seaJS 来编写模块化,特点:支持动态引入依赖文件

define(function(require, exports, module) {  
  var indexCode = require('./index.js');
});

CommonJS: nodejs 中自带的模块化。

var fs = require('fs');

UMD:兼容AMD,CommonJS 模块化语法。

webpack(require.ensure):webpack 2.x 版本中的代码分割。

ES Modules: ES6 引入的模块化,支持import 来引入另一个 js 。

import a from 'a';

ES Modules与common.js区别

  1. 输出值
  • es6输出的是一个值的引用( ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。)
  • common 输出的是一个值的拷贝(模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。)
  1. 加载方式
  • common 运行时加载 (因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成)
  • es6 编译时输出接口 (ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。)

AMD,CMD用的不多,主要讲一下CommonJS和ESModule

模块的特性

  • 为创建一个内部作用域而调用了一个包装函数。
  • 包装函数的返回值至少包含一个对内部函数的引用,这样才会创建涵盖整个包装函数内部作用域的闭包。

CommonJS

特点: requiremodule.exportsexports CommonJS 一般用在服务端或者Node用来同步加载模块,它对于模块的依赖发生在代码运行阶段,不适合在浏览器端做异步加载。 exports实际上是一个对module.exports的引用:

    exports.add = function add () {/* 方法 */}
    // 等同于
    module.exports.add = function add () {/* 方法 */}

但注意,不能给exports赋值,否则会断开与module.exports的连接。

ES6 Module

特点: importexport ES6模块化不是对象,import会在JavaScript引擎静态分析,在编译时就引入模块代码,而并非在代码运行时加载,因此也不适合异步加载。 在HTML中如果要引入模块需要使用

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

ESModule的优势:

  • 死代码检测和排除。我们可以用静态分析工具检测出哪些模块没有被调用过。比如,在引入工具类库时,工程中往往只用到了其中一部分组件或接口,但有可能会将其代码完整地加载进来。未被调用到的模块代码永远不会被执行,也就成为了死代码。通过静态分析可以在打包时去掉这些未曾使用过的模块,以减小打包资源体积。
  • 模块变量类型检查。JavaScript属于动态类型语言,不会在代码执行前检查类型错误(比如对一个字符串类型的值进行函数调用)。ES6 Module的静态模块结构有助于确保模块之间传递的值或接口类型是正确的。
  • 编译器优化。在CommonJS等动态模块系统中,无论采用哪种方式,本质上导入的都是一个对象,而ES6 Module支持直接导入变量,减少了引用层级,程序效率更高。

二者的差异

CommonJS模块引用后是一个值的拷贝,而ESModule引用后是一个值的动态映射,并且这个映射是只读的。

  • CommonJS 模块输出的是值的拷贝,一旦输出之后,无论模块内部怎么变化,都无法影响之前的引用。
  • ESModule 是引擎会在遇到import后生成一个引用链接,在脚本真正执行时才会根据这个引用链接去模块里面取值,模块内部的原始值变了import加载的模块也会变。

CommonJS运行时加载,ESModule编译阶段引用。

  • CommonJS在引入时是加载整个模块,生成一个对象,然后再从这个生成的对象上读取方法和属性。
  • ESModule 不是对象,而是通过export暴露出要输出的代码块,在import时使用静态命令的方法引用指定的输出代码块,并在import语句处执行这个要输出的代码,而不是直接加载整个模块。

Originally posted by @Reaper622 in https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/28#issuecomment-562807639

CodingMeUp avatar Jun 23 '20 15:06 CodingMeUp

https://www.yuque.com/docs/share/9f219af8-12a5-4441-978f-201ef03987ab?

CodingMeUp avatar May 10 '21 03:05 CodingMeUp