javascript-AMD / CMD / UMD / CommonJS / ES Module/可选链


请你讲一下对于JS中模块的理解,Commonjs、 AMD和CMD分别有什么特点?
一个模块是能实现特定功能的文件,有了模块就可以方便的使用别人的代码,想要什么功能就能加载什么模块。
模块化开发方便代码的管理,提高代码复用性,降低代码耦合,每个模块都会有自己的作用域,当前流行的模块化规范有CommonJS,AMD,CMD,ES6的import;

1. CommonJS

CommonJS的主要实践者就是nodejs;一般对模块输出用module.exports去输出,用require去引入模块, CommonJS一般采用同步加载 ;CommonJS 模块输出的是一个值的拷贝;
EG:
1° 对于基本数据类型, CommonJS 模块无论加载多少次, 都只会在第一次加载时运行一次, 以后再加载, 返回的都是第一次运行结果的缓存, 除非手动清除系统缓存;

 mod.incCounter() 不会影响 mod.counter,
// lib.js
var counter = 3
function incCounter() {
counter++
}
module.exports = {
counter: counter,
incCounter: incCounter,
}

// main.js
var mod = require('./lib')
console.log(mod.counter) // 3
mod.incCounter()
console.log(mod.counter) // 3

2° 如果是个对象, 修改里面的值, 会影响原对象

// lib.js
var obj = { name: 'Yancey', age: 18 }
function incCounter() {
 obj.name = 'Leo'
}
module.exports = {
 obj: obj,
 incCounter: incCounter,
}

// main.js
var mod = require('./lib')
console.log(mod.obj) // { name: 'Yancey', age: 18 }
mod.incCounter()
console.log(mod.obj) // { name: 'Leo', age: 18 }

3°如果把对象改成其他类型, 原变量不受响应.

// lib.js
var obj = { name: 'Yancey', age: 18 }
function incCounter() {
  obj = '沙雕'
}
module.exports = {
  obj: obj,
  incCounter: incCounter,
}

// main.js
var mod = require('./lib')
console.log(mod.obj) // { name: 'Yancey', age: 18 }
mod.incCounter()
console.log(mod.obj) // { name: 'Yancey', age: 18 }

// lib.js

2.ES Module

1° ES6 模块输出的是值的引用
JS 引擎对脚本静态分析的时候, 遇到模块加载命令 import 就会生成一个只读引用. 等到脚本真正执行的时候, 再根据这个只读引用到被加载的模块中取值. 因此, ES6 模块是动态引用, 并且不会缓存值, 模块里的变量绑定其所在的模块.

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

// main.js
//只读引用 counter
import { counter, incCounter } from './lib'
//模块中取值
console.log(counter) // 3
incCounter()
//不会缓存值
console.log(counter) // 4

2° ES6 输入的模块变量只是一个"符号连接", 所以这个变量是只读的, 对它重新赋值会报错

// lib.js
export let obj = {}

// main.js
import { obj } from './lib'
obj.prop = 123 // 可以
obj = {} // 报错

3. AMD

AMD主要采用异步加载模式,AMD的主要实践有require.js

使用 require.js

// 定义没有依赖的模块
define(function () {
  return 模块
})

// 定义有依赖的模块
define(['module1', 'module2'], function (m1, m2) {
  return 模块
})

//引入使用模块
require(['module1', 'module2'], function (m1, m2) {
  // 使用m1/m2
})

4.CMD

CMD是主要实践是Sea.js,与AMD相似,AMD依赖前置加载,提前加载执行,CMD就近加载,延迟加载 AMD用户体验好,因为模块提前执行了;CMD性能好,因为只有用户需要的时候才执行。
使用 sea.js

// 定义没有依赖的模块
define(function (require, exports, module) {
  exports.xxx = value
  module.exports = value
})

// 定义有依赖的模块
define(function (require, exports, module) {
  // 引入依赖模块(同步)
  var module2 = require('./module2')
  // 引入依赖模块(异步)
  require.async('./module3', function (m3) {})
  // 暴露模块
  exports.xxx = value
})

// 引入使用模块
define(function (require) {
  var m1 = require('./module1')
  var m4 = require('./module4')
  m1.show()
  m4.show()
})

5.UMD

所谓UMD (Universal Module Definition), 就是一种 JavaScript 通用模块定义规范, 让你的模块能在 JavaScript 所有运行环境中发挥作用.

前端模块规范有:AMD,CMD,CommonJs,UMD

一.总览
1.浏览器端
AMD是requireJs在推广过程中对模块定义的规范(异步模块规范) // 依赖前置(需要用的时候在前面加载好,引用好,回调再使用) 所有模块依赖前置
CMD是seaJs在推广过程中对模块定义的规范(普通模块规范) //seaJs的一个标准 是淘宝的一个标准 依赖就近什么地方使用,什么地方就用 即用即返回 define(function(require,export,module))
AMD
2.node端
commonJs(同步模块规范)
module.exports
exports.area=function(){
return Math.PIrr
}
3.浏览器和node兼容端
UMD(通用模块规范)
4.ES6内置模块化module
import引入一个模块
export [default] 对外暴露一个对象

二.应用
1.AMD
提前执行(异步加载:依赖先执行)–依赖前置
提供define(定义模块)和require(调用模块)方法来进行模块化编程
define(id?,dependencies?,factory);
require([module], callback);

//Utils模块
define(function(){
function Utils(name) {
this._name = name;
}
Utils.add = function(a, b) {
return a + b;
}
return Utils;
})

//加载和使用
// 配置各个模块地址
require.config({
 paths: {
     “Utils”: “./js/lib/Utils”
  },
shim: {}    
});
//加载指定模块
require([“Utils”], function(Utils) {
});

2.CMD
延迟执行(按需加载)–依赖就近
在 CMD 规范中,一个模块就是一个文件
define(factory); //factory可以是个函数,也可以是个对象或字符串
define(id?, deps?, factory) //字符串id-模块标识,数组deps-依赖模块(define(function(require, exports){

//require(id) 接受 模块标识 作为唯一参数
var a = require(‘./a’);
a.doSomething()

//require.async(id, callback?) 方法用来在模块内部异步加载模块,并支持指定回调
require.async(‘./b’, function(b) {
b.doSomething();
});
//加载多个模块
require.async([‘./c’, ‘./d’], function(c, d) {
c.doSomething();
d.doSomething();
});

//require.resolve(id)模块系统内部的路径解析机制来解析并返回模块路径
console.log(require.resolve(‘./b’));

// 对外提供 foo 属性
exports.foo = ‘bar’;
// 对外提供 doSomething 方法
exports.doSomething = function() {};
//return 直接向外提供接口
return {
foo: ‘bar’,
doSomething: function() {}
};
//exports 仅仅是 module.exports 的一个引用,并不会改变 module.exports 的值。因此给 exports 赋值是无效的,不能用来更改模块接口
module.exports = {
foo: ‘bar’,
doSomething: function() {}
};

})

3.commonJs
加载模块是同步的,只有加载完成后才能执行后面的操作
模块分为:
(1)模块引用(require)
(2)模块定义(exports)
(3)模块标识(module)

//模块
function Utils(name) {
this._name = name;
}
Utils.add = function(a, b) {
return a + b;
}
// 将类 Utils 作为当前文件的模块导出
module.exports = Utils;

//加载模块
var Utils = require(‘./Utils.js’);
console.log(Utils.add(10, 20));

总结

1.CommonJS 与 ES6 Module
CommonJS 是运行时加载, 这种特性不能使用 Tree-shaking; ES6 Module 是编译时输出接口, 可使用 Tree-shaking

2.CMD 和 AMD 的异同
相同点: 都是异步加载
不同点: AMD 依赖前置, 提前执行, js 可以方便知道依赖模块是谁, 立即加载; 而 CMD 就近依赖, 需要使用把模块变为字符串解析一遍才知道依赖了那些模块

可选链

可选链(Optional chaining)
是一种以安全的方式去访问嵌套的对象属性,即使某个属性根本就不存在。
这是一项新的提案,老旧浏览器可能需要 polyfills。

1.短路

user?.address?.street

2.---------?.()

user2.admin?.(); // 啥都没有(因为没有这样的方法)

3.---------?.[]
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 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: CommonJSAMDCMDES6是JavaScript使用的模块系统。它们都试图将代码组织为可重用的模块,但它们在一些方面不同。 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、付费专栏及课程。

余额充值