关于js 模块化

(本文为个人笔记。欢迎转载,转载请注明出处。文章内容引用在本文底部。)

前言

模块化的开发方式可以提高代码复用率,方便进行代码的管理.。通常一个文件就是一个模块,有自己的作用域,只向外暴露特定的变量和函数。目前流行的js模块化规范有:CommonJS(node.js)、AMD、CMD (sea.js)以及ES6的模块系统。


CommonJS规范(node 模块 )

commonJS用同步的方式加载模块。在服务端,模块文件都存在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。

硬盘 I/O网速 I/O
HDD: 100 MB/sADSL: 4 Mb/s
SSD: 600 MB/s4G: 100 Mb/s
SATA-III: 6000 Mb/sFiber: 100 Mb/s
AMD规范 (RequireJS 对模块定义的规范化产出)

AMD规范采用异步方式加载模块,模块的加载不影响他后面语句的运行。
require.js实现AMD规范的模块化:用require.config()指定引用路径等,用define()定义模块,用require()加载模块。

// AMD recommended style
define(["a", "b"], function(a, b){ // 依赖前置
    a.doSomething();
    b.doSomething();
})
CMD(SeaJS 对模块定义的规范化产出)

与AMD很类似,不同点在与:AMD推崇依赖前置、提前执行、CMD推崇依赖就近、延迟执行。

// CMD recommanded
define(function(require, exports, module){
    var a = require("a");
    a.doSomething();
    var b = require("b");
    b.doSomething();    // 依赖就近,延迟执行
})
ES6 Module

ES6在语言标准的层面上,实现了模块功能(官方)。旨在成为浏览器和服务器的通用模块解决方案。
其模块功能主要由两个命令构成:exportimportexport命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

export写法
/** 定义模块 math.js **/
var basicNum = 0;
var add = function (a, b) {
    return a + b;
};
export { basicNum, add };

/** 引用模块 **/
import { basicNum, add } from './math';
function test(ele) {
    ele.textContent = add(99 + basicNum);
}
export default
/** export default **/
//定义输出
export default { basicNum, add };
//引入
import math from './math';
function test(ele) {
    ele.textContent = math.add(99 + math.basicNum);
}

ES6的模块不是对象,import命令会被 JavaScript 引擎静态分析,在编译时就引入模块代码,而不是在代码运行时加载,所以无法实现条件加载。也正因为这个,使得静态分析成为可能。


ES6 模块与 CommonJS 模块的差异

1. CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值
  • ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
--------CommonJS-----↓↓↓↓
// 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
----------ES6--------↓↓↓↓
// lib.js
export let counter = 3;
export function incCounter() {
  counter++;
}

// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4
2. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  • 运行时加载:CommonJS 模块就是对象;即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。

  • 编译时加载:ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,import时采用静态命令的形式。即在import时可以指定加载某个输出值,而不是加载整个模块,这种加载称为“编译时加载”。


插件兼容

开发插件时,为了兼容不同规范,可以用一下代码:

;(function(){
    function MyModule() {
        // ...
    }
    var moduleName = MyModule;
    if (typeof module !== 'undefined' && typeof exports === 'object' && define.cmd) { //cmd
        module.exports = moduleName;
    } else if (typeof define === 'function' && define.amd) { // amd
        define(function() { return moduleName; });
    } else { //others
        this.moduleName = moduleName;
    }
}).call(function() {
    return this || (typeof window !== 'undefined' ? window : global);
});


参考及引用地址 (感谢作者)
http://huangxuan.me/js-module-7day/#/
https://juejin.im/post/5aaa37c8f265da23945f365c
http://es6.ruanyifeng.com/#docs/module-loader
https://www.jianshu.com/p/58fb2dafa584

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值