开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 18 天,点击查看活动详情
AMD、CMD、CommonJs 详解
CommonJS
CommonJS 是以在浏览器环境之外构建 javaScript 生态系统为目标而产生的写一套规范,主要是为了解决 javaScript 的作用域问题而定义的模块形式,可以使每个模块它自身的命名空间中执行,该规范的主要内容是,模块必须通过 module.exports 导出对外的变量或者接口,通过 require() 来导入其他模块的输出到当前模块的作用域中;目前在服务器和桌面环境中,node.js 遵循的是 CommonJS 的规范; CommonJS 对模块的加载时同步的; CommonJS 模块的特点:
1-> 所有代码都运行在模块作用域,不会污染全局作用域。
Node 应用由模块组成,采用 CommonJS 模块规范。 每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。 2-> 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
3-> 模块加载的顺序,按照其在代码中出现的顺序。
实际应用:
require 引入模块 输入模块#
使用方法:require('模块名') 不指定路径: 先找系统模块-> 再从项目环境找 node_modules|bower_components (依赖模块)->not found 指定路径 : 指定路径 -> not found require(./utils).xx 按需引用
exports 导出,批量输出 都是属性
exports.自定义属性=值(any) 输出带接口 require(模块文件名)=modA modA 是个模块实例{自定义属性}
module 默认输出 any 只能输出一次
module.exports = {
自定义属性:值
}
module.exports=对象/fn/class require('..')=modA modA 是一个 fn 或者是类 class 本身.
注:commonJS 是 nodejs 默认模块管理方式,不支持 es6 的模块化管理方式,但支持所有 es6+语法.
AMD
AMD 主要是为前端 js 的表现指定的一套规范;而 CommonJS 是主要为了 js 在后端的表现制定的,它不适合前端; AMD 是 Asynchronous Module Definition 的缩写,意思是 异步模块定义;采用的是异步的方式进行模块的加载,在加载模块的时候不影响后边语句的运行; AMD 也是采用 require() 语句加载模块的,但是不同于 CommonJS ,它有两个参数;require(['模块的名字'],callBack);requireJs 遵循的就是 AMD 规范;
CMD
CMD 是 Common Module Definition 的缩写,是 seajs 推荐的一套规范,CMD 也是通过异步的方式进行模块的加载的,不同于 AMD 的是,CMD 的加载是按照就近规则进行的,AMD 依赖的是前置;CMD 在加载的使用的时候会把模块变为字符串解析一遍才知道依赖了哪个模块; CommonJS 其实也有浏览器端的实现,原理是先将所有模块都定义好并通过 id 索引方便的在浏览器环境中进行解析; AMD 的实现其实是通过 define 函数定义在闭包中,例如:define(id?: String,dependencies?: String[],factory: Function | Object); 其中,id 是模块的名字,是一个可选的参数;dependencied 指定了所要依赖的模块列表,是一个数组,每个依赖的模块的输出将作为参数一次传入 factory 中;如果没有指定 dependencies 的话,那么默认的就是 ["require","exports","module"];factory 包括了模块的具体实现,它是一个函数或者对象;如果是函数,那么它的返回值就是模块的输出接口或者值;
import 和 request 的区别
区别 1:模块加载的时间 require:运行时加载 import:编译时加载(效率更高)【由于是编译时加载,所以 import 命令会提升到整个模块的头部】 在这里可以做 tree-shaking
test(); import { test} from '/test';
上面的代码不会报错,正常执行
区别 2:模块的本质 require:模块就是对象,输入时必须查找对象属性 import:ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,再通过 import 命令输入(这也导致了没法引用 ES6 模块本身,因为它不是对象)。由于 ES6 模块是编译时加载,使得静态分析成为可能。有了它,就能进一步拓宽 JavaScript 的语法,比如引入宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能。
// CommonJS 模块 let { exists, readFile } = require('fs'); // 等同于 let fs = require('fs'); let exists = fs.exists; let readfile = fs.readfile;
上面 CommonJs 模块中,实质上整体加载了 fs 对象(fs 模块),然后再从 fs 对象上读取方法
// ES6 模块 import { exists, readFile } from 'fs';
上面 ES6 模块,实质上从 fs 模块加载 2 个对应的方法,其他方法不加载
区别 3:严格模式 CommonJs 模块和 ES6 模块的区别: (1)CommonJs 模块默认采用非严格模式 (2)ES6 的模块自动采用严格模式,不管你有没有在模块头部加上 “use strict”; (3)CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用,举例如下
// m1.js export var foo = 'bar'; setTimeout(() => foo = 'baz', 500); // m2.js import {foo} from './m1.js'; console.log(foo); //bar setTimeout(() => console.log(foo), 500); //baz
ES6 模块之中,顶层的 this 指向 undefined ,即不应该在顶层代码使用 this
commonJs 中顶层的 this 就是 module.exports
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 18 天,点击查看活动详情