JS模块化——CommonJS AMD CMD UMD ES6 Module 比较

1. 模块使用方式

CommonJS :require 引用模块    module.exports 暴露接口
AMD:require 引用模块   使用 define 函数的 return 暴露接口

CMD:require 引用模块   module.exports 或 exports 暴露接口

ES6:import 引用模块     export default 暴露接口

2. 模块加载方式

CommonJS :运行时加载,一个模块就是一个对象,
加载一个模块就是加载这个模块的所有方法,然后读取其中需要的方法。

  AMD:并行加载,提前执行。

  CMD:并行加载,按需执行。

  ES6 :编译时加载,在模块编译时就完成加载,
  引用的时候只加载需要的方法,其他方法不加载。

1CommonJS(node.js)

CommonJS是服务器模块的规范,Node.js采用了这个规范。

根据 CommonJS 规范,一个单独的文件就是一个模块,
每一个模块都是一个单独的作用域,
在一个文件定义的变量(还包括函数和类)
,都是私有的,对其他文件是不可见的)
CommonJS规范加载模块是同步的,
也就是说,只有加载完成,才能执行后面的操作

Node.js 主要用于服务器编程,加载的模块文件一般都已经存在本地硬盘,
加载起来较快,不用考虑异步加载的方式,
所以 CommonJS 的同步加载模块规范是比较适用的。
但如果是浏览器环境,要从服务器加载模块,这是就必须采用异步模式。
所以就有了 AMD,CMD 等解决方案。

导出
module.exports = {
  x: x,
  addX: addX,
};

使用
let math = require('./math.js');
console.log('math.x',math.x);
console.log('math.addX', math.addX(4));

2、AMD(requireJS)

AMD 规范加载模块是异步的,并允许函数回调,
不必等到所有模块都加载完成,后续操作可以正常执行

3、CMD(SeaJS)

通用模块定义

4、AMDvsCMD

二者区别主要表现在模块初始化时机
从规范上来说,AMD 更加简单且严谨,适用性更广,

//AMD
define(['./a','./b'], function (a, b) {
 
    //依赖一开始就写好
    a.test();
    b.test();
});
 
//CMD
define(function (requie, exports, module) {
     
    //依赖可以就近书写
    var a = require('./a');
    a.test();
     
    ...
    //软依赖
    if (status) {
        var b = requie('./b');
        b.test();
    }
});

4、UMD

即通用模块定义。UMD 是AMD 和 CommonJS的糅合。

AMD 模块以浏览器第一的原则发展,异步加载模块。
CommonJS 模块以服务器第一原则发展,选择同步加载。它的模块无需包装(unwrapped modules)。
这迫使人们又想出另一个更通用的模式 UMD(Universal Module Definition),实现跨平台的解决方案。

UMD 先判断是否支持 Node.js 的模块(exports)是否存在,存在则使用 Node.js 模块模式。
再判断是否支持 AMD(define 是否存在),存在则使用 AMD 方式加载模块。
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['b'], factory);
  } else if (typeof module === 'object' && module.exports) {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(require('b'));
  } else {
    // Browser globals (root is window)
    root.returnExports = factory(root.b);
  }
}(this, function (b) {
  //use b in some fashion.
  // Just return a value to define the module export.
  // This example returns an object, but the module
  // can return a function as the exported value.
  return {};
}));

5、ES6模块

ES6模块和CommonJS区别

ES6 模块输出的是值的引用,输出接口动态绑定,而 CommonJS 输出的是值的拷贝。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。

CommonJS 输出值的拷贝

CommonJS 模块输出的是值的拷贝(类比于基本类型和引用类型的赋值操作)。对于基本类型,一旦输出,模块内部的变化影响不到这个值。对于引用类型,效果同引用类型的赋值操作。

ES6 输出值的引用

ES6 模块是动态关联模块中的值,输出的是值得引用。原始值变了,import 加载的值也会跟着变。

CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。

这是因为,CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

ES6 模块是编译时输出接口,因此有如下2个特点
import 命令会被 JS 引擎静态分析,优先于模块内的其他内容执行
export 命令会有变量声明提升的效果

import 优先执行
在文件中的任何位置引入 import 模块都会被提前到文件顶部

import和 export

 import 优先执行
	在文件中的任何位置引入 import 模块都会被提前到文件顶部

 export 命令变量提升效果
	由于 import 和 export 是静态执行,所以 import 和 export 具有变量提升效果。
	即 import 和 export 命令在模块中的位置并不影响程序的输出。
// a.js
import { foo } from './b';
console.log('a.js');
export const bar = 1;
export const bar2 = () => {
  console.log('bar2');
}
export function bar3() {
  console.log('bar3');
}

// b.js
export let foo = 1;
import * as a from './a';
console.log(a);

// 执行结果:
// { bar: undefined, bar2: undefined, bar3: [Function: bar3] }
// a.js

a 模块引用了 b 模块,b 模块也引用了 a 模块,
export 声明的变量也是优于模块其它内容的执行的。
但具体对变量赋值需要等到执行到相应代码的时候。

ES6模块和CommonJS相同点

重复引入某个相同的模块时,模块只会执行一次。

CommonJS 模块循环依赖
	在 CommonJS 规范中,当遇到 require() 语句时,会执行 require 模块中的代码,
	并缓存执行的结果,当下次再次加载时不会重复执行,而是直接取缓存的结果。
	正因为此,出现循环依赖时才不会出现无限循环调用的情况。

ES6 模块循环依赖
	跟 CommonJS 模块一样,ES6 不会再去执行重复加载的模块,
	又由于 ES6 动态输出绑定的特性,能保证 ES6 在任何时候都能获取其它模块当前的最新值。

动态import

不可以

ES6 模块在编译时就会静态分析,优先于模块内的其他内容执行

if(some condition) {
  import a from './a';
}else {
  import b from './b';
}

// or 
import a from (str + 'b');
可以动态
// a.js
const str = './b';
const flag = true;
if(flag) {
  import('./b').then(({foo}) => {
    console.log(foo);
  })
}
import(str).then(({foo}) => {
  console.log(foo);
})

// b.js
export const foo = 'foo';

// babel-node a.js
// 执行结果
// foo
// foo

动态的 import() 提供一个基于 Promise 的 API
如果在浏览器端的 import() 的用途就会变得更广泛,比如 按需异步加载模块

webpack中加载3种模块 | 语法

ES6 模块

import MyModule from ‘./MyModule.js’;

CommonJS(Require)

var MyModule = require(‘./MyModule.js’);

AMD

define([‘./MyModule.js’], function (MyModule) {});

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: CommonJSAMD/CMD是两种不同的模块化规范,而ES6则是JavaScript的新标准,也包含了模块化的支持。 CommonJS主要用于服务器端的模块化,其特点是同步加载模块,模块输出的是一个对象,可以通过require()方法加载模块。 AMD/CMD则主要用于浏览器端的模块化,其特点是异步加载模块,模块输出的是一个函数,可以通过define()方法定义模块。 ES6模块化则是JavaScript的新标准,其特点是静态加载模块,模块输出的是一个变量,可以通过import和export语句加载和定义模块。 总的来说,CommonJSAMD/CMD是旧的模块化规范,而ES6则是新的标准,具有更好的性能和可读性。 ### 回答2: CommonJS是一个模块规范,旨在使JavaScript在服务器端上运行。它在Node.js上得到广泛应用,主要是用于模块管理和代码复用。它定义了模块如何定义以及如何导出和导入模块。 AMDCMD是两个常用的模块规范,旨在更好地管理浏览器端的模块。AMDCMD规范都优化了服务器端的加载速度,提高了代码复用性。 ES6是一个新版的JavaScript规范,它增加了许多新的语言特性和语法糖,使得JavaScript更具有可读性和可维护性。ES6规范中引入了模块的概念,通过import和export可以轻松管理模块,并且JS引擎会进行编译优化以提高性能。 CommonJSAMD/CMD的主要区别在于模块的加载方式。CommonJS采用同步加载方式,即导入模块时会等待所有依赖模块都加载完毕后再执行导入操作。这会造成一定的阻塞,但是可以保证依赖关系正确。而AMD/CMD采用异步加载方式,即采用回调函数的方式导入模块,不会造成阻塞,但是需要手动管理依赖关系。 ES6模块的最大优点在于静态编译。在使用ES6模块时,浏览器可以在代码加载时对模块进行静态分析,从而明确哪些模块需要导入和导出,它们的依赖关系以及导入的值。这是在CommonJSAMD/CMD等模块规范中无法做到的。ES6模块的缺点是目前还不是所有的浏览器都支持。 ### 回答3: CommonJSAMDCMDES6JavaScript使用的模块系统。它们都试图将代码组织为可重用的模块,但它们在一些方面不同。 CommonJS是一个使用Node.js的模块系统,它允许在服务器端和客户端共享模块。CommonJS模块是同步加载的,这意味着当模块被请求时,它会立即加载模块,并立即执行模块的代码。 AMD(异步模块定义)是在浏览器环境中使用的模块系统,它允许异步加载模块。当一个模块被请求时,AMD并不会像CommonJS那样立即加载它,而是等待其他模块完成加载。然后,当模块被加载和运行时,AMD会运行任何模块和依赖项的回调函数。 CMD(通用模块定义)是一个应用于浏览器和服务器端的模块系统,它的特点是就近依赖,在需要时才进行依赖的加载。CMD模块是通过define函数来定义的。在调用define时,会传递一个回调函数,该回调函数可以使用require来访问其他模块。 ES6模块是JavaScript的原生模块系统,它允许在JavaScript中定义模块。ES6模块是静态的,这意味着每个模块都是在编译时确定的。ES6模块支持默认导出和命名导出。 在总体上,CommonJS适合于服务器端,AMDCMD适合于浏览器端,而ES6则是一个全面的模块系统,适用于任何环境。不同的模块系统在实现上有所不同,选择哪种类型的模块系统需要根据具体情况进行判断。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值