Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
CodingMeUp opened this issue Jun 23, 2020 · 2 comments

Comments

@CodingMeUp
Copy link
Owner

No description provided.

@CodingMeUp
Copy link
Owner Author

CodingMeUp commented Jun 23, 2020

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

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 Advanced-Frontend/Daily-Interview-Question#28 (comment)

@CodingMeUp
Copy link
Owner Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant