commonJS
模块引用
var add = require('./add.js');
var config = require('config.js');
var http = require('http');
模块定义
module.exports.add = fucntion() {...}
module.exports = fucntion() {return ...}
一个文件代表一个模块,一个模块除了自己的函数作用域之外,最外成还有一个模块作用域,module 代表这个模块,exports 是 module 的属性。require() 也在这个模块的上下文中,用来引入外部模块。
模块表示
规范:
- 必须是字符串
- 可以是相对路径
- 可以是绝对路径
- 可以省略后缀名
NodeJS中模块化
一个文件是一个模块 —— module
一个模块就是一个 Module 实例
Node 中Module 的构造函数:
function Module(id, parent) {
this.id = id;
this.exports = {};
this.parent = parent;
if (parent && parent.children) {
parent.children.push(this);
}
this.filename = null;
this.loaded = false;
this.children = [];
}
// 实例化一个模块
var module = new Module(filename, parent);
node 模块分类
node 模块的引入一般需要经过三个步骤:
- 路径分析
- 文件定位
- 编译执行
核心模块会省略文件定位和编译执行这两部,加载速度比一般的模块更快。
前端模块化
前端模块化和服务端模块化的区别
- 服务端加载模块从硬盘读取,消耗时间可以忽略
- 浏览器需要先从服务器端下载这个文件,再用 commonJS 的require 方式加载模块,需要等下载完毕,并运行之后才能得到所需的API
commonJS 不适合前端模块的原因:
commonJS是同步加载的,如果遇到通过http请求的模块,会阻塞代码的执行。
因此现在前端都是使用异步模块加载。
AMD(asynchronous Module Definition) & RequireJS:
与commonJS 相比,就是可以异步加载模块,不会阻塞。
RequireJS —— AMD 规范的实现。
运行时加载:
- CommonJS 和AMD模块都只能在运行时确定模块之间的依赖关系
- require 一个模块的时候,模块会先被执行,并返回一个对象,这个对象是整体加载的。
CMD(common Module Definition) $ seajs
CMD:通用模块规范
SeaJS:CMD的实现
CMD 与AMD 的主要区别在于定义模块和依赖引入部分。AMD需要在声明模块的时候指定所有的依赖,通过形参传递到模块内容中:
// AMD
defien(['dep1', 'dep2'], function(dep1, dep2) {
return function(){};
})
// CDM
defin(factory);
CMD支持动态引入,require, exports 和 module 通过形参传递给模块,在需要依赖模块式,随时调用require() 引入
UMD(universal Module Definition)
ES6的模块
ES6 在语言层面实现了模块功能,是编译时加载。
export
export var name = 'xxx';
export function foo(x, y) {};
// 常用
const name = 'xxx';
const age = 18;
export {name, age};
// as 可以将一个模块输出多次
const s = 1;
export {s as t, s as m};
import
import {name, age} from './a.js';
import {name as personName} from './a.js';
// person.js
export name = 'xxx';
export age = 18;
// 逐一加载
import {name, age} from './person.js';
// 整体加载
import * as person from './person.js';
person.name;
person.age;
import 具有变量提升的特性,可以提前访问
export default
使用 export default 命令是, import 不需要加 { }。不使用 export default 时,import 必须加 { }
// person.js
export function getName() {}
import {getName} from ''
------
// person.js
export default function getName() {}
import getName from './person.js'
export default 其实是导出一个叫做 default 的变量,所以后面不能再跟变量声明语句。
可以同时使用 export 和 export default
// person.js
export name = 'xxx';
export default function getName() {}
import getName, {name} from './person.js'
ES6 和 commonJS 在模块加载上的区别
// ES6 编译时加载,只加载 path 模块的3个方法,其他不加载
// 遇到import 时生成一个动态的只读引用,当真正需要的时候再到模块里取值,所以ES6 的模块是动态引用,且不会缓存。
import {basename, direname, parse} from 'path';
// commonJs 在运行时,将path运行一遍,返回一个对象,并将这个对象缓存起来,以后的加载都是读取这个缓存值。
let {basename, dirname, parse} = require('path');
因为 CommonJS 输出的是值的拷贝,所以当模块中的值在引用之后改变时,不会影响到输出结果。