JS模块化

更新日期: 2019-02-27阅读: 3.2k标签: 模块化

模块化

目前比较流行的 JS 模块化方案有 CommonJS、AMD、CMD 以及 ES6 Module,还有个 UMD 方案。


CommonJS

CommonJS 是服务器端的模块化方案,nodeJs 就采用了这种方案。在 CommonJS 规范中,一个文件即一个模块,用module.exports和exports定义模块输出的接口,用require加载模块。

// math.js
function add(a, b) {
  return a+b;
}

module.exports = {
    add: add
}

// 也可以这样写
exports.add = (a, b) => a+b;
// main.js
const add require('./math');
add(1, 2); // 3

CommonJs采用同步加载方式,对于服务器和本地环境来说,同步加载是非常快的,但对于浏览器来说,就不行了,限于网络因素,异步加载才是比较好的方案。


AMD

为了解决浏览器模块化的问题,AMD 和 CMD 这两个异步加载方案被提出,requireJS可以说是 AMD 方案的最佳实践。

// index.html
// before
<script src="..."></script>
<script src="..."></script>
<script src="..."></script>
    
// AMD - requireJS
<script src="require.js" data-main="main.js"></script>

在 re在 requireJS 中用define定义模块,require载入模块,require.config用来配置路径。

// math.js
// define(id?, dependencies?, factory)
define(() => {
  return {
    add: (a, b) => a+b
  }
});
// main.js
require.config({
    baseUrl: 'js/lib',
    paths: {
        // 左边是模块ID,右边是路径
        // 这里的路径是 js/lib/jquery.js
        jquery: 'jquery',
        // 这里的路径是 js/lib/math.js
        math: 'math'
    }
});

// require([modlue], callback)
require(['jquery', 'math'], ($, math) => {
  // do something
});

需要注意的是,AMD 方案是依赖前置的,提前执行。

// AMD 依赖前置,提前执行
define(['a', 'b'], function(a, b){
    // a 和 b谁先加载完,谁就先执行
    // 并不按照代码顺序同步执行
    a.doSomething();
    b.doSomething();
})

官网:requireJS


CMD

与 AMD 不同,CMD 是依赖就近,延迟执行,requireJS 也支持 CMD 写法。

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

阿里的 seaJS 可以说是比较出名的 CMD 实例项目,但现在都有更好的方案来替代它们了。

需要注意的是,两者只是对依赖模块的执行时机不一样,并非加载时机不一样,模块的加载时机都是一样的,它们都是异步加载的。AMD是模块加载完就会执行模块,所有模块都加载执行完就进入require的回调函数,CMD 则是所有模块都加载完,但不执行,需要注意的是,两者只是对依赖模块的执行时机不一样,并非加载时机不一样,模块的加载时机都是一样的,它们都是异步加载的。AMD是模块加载完就会执行模块,所有模块都加载执行完就进入require的回调函数,CMD 则是所有模块都加载完,但不执行,等到require这个模块时才执行。

CMD标准:https://github.com/cmdjs
AMD标准:https://github.com/amdjs


UMD

UMD 是 CommonJS 和 AMD 的混合,它会判断当前环境支持哪个就使用哪个,这个就不多说了。


ES6 Module

ES6 Module 横空出世,混乱的时代结束了。

ES6 在语言标准层面定义模块化规范,而且简洁明了,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

ES6 Module 主要使用export输出,import加载。

// math.js
let PI = 3.1415;
let circleArea = (x) => x*PI;

export {PI, circleArea};

// 也可以这样写
export let PI = 3.1415;
export let circleArea = (x) => x*PI;
// main.js
import {PI, circleArea} from './math.js'
circleArea(1); // 3.1415

// 也可以这样写
import * as math from './math.js'
math.circleArea(1); // 3.1415

还有一个export default命令:

// 使用 export default 输出的模块只能有一个输出
export default () => concole.log('hhh');

需要注意的是,CommonJS 输出的是值的拷贝,对于基本数据类型是直接拷贝,即缓存模块,但复杂数据类型是浅拷贝,因此修改一个模块中的值,是会改变另一个模块的值的。 require模块的时候,就会执行整个模块,即运行时加载,然后exports输出,缓存输出值,再次require时,会直接在缓存内取值。

而 ES6 Module 是编译时加载,import加载的是值的引用,加载进来的值是不能被修改的,即值是只读的,而且不论是基本数据类型还是复杂数据类型,修改原模块的值修改,import得到的值也是会改变,即值是动态的。

  • CommonJS 输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 是运行时加载,ES6 模块是编译时输出接口。

至于循环加载问题(a 依赖 b,b 依赖 c,c 依赖 a):

CommonJS 循环加载时,因为是属于加载时执行,所以一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分就不输出。而对于 ES6 Module来说,因为是动态引用,所以出现循环加载时,只要两个模块之间存在某个引用,即取值的时候能够真正的取到值,代码就能够执行。

// node 环境
// a.mjs
import {bar} from './b';
console.log('a.mjs');
console.log(bar());
function foo() { return 'foo' }
export {foo};

// b.mjs
import {foo} from './a';
console.log('b.mjs');
console.log(foo());
function bar() { return 'bar' }
export {bar};
/* 结果
b.mjs
foo
a.mjs
bar
*/

执执行a.mjs不会报错,因为函数声明会提升,在执行import {bar} from ‘./b‘时,函数foo就已经有定义了,所以b.mjs加载的时候不会报错。这也意味着,如果把函数foo改写成函数表达式,也会报错。


备注

规范真多,但我也只用过 CommonJS 和 ES6 Module,而且 ES6 还要靠 babel


链接: https://www.fly63.com/article/detial/2144

一览js模块化:从CommonJS到ES6

模块化是指把一个复杂的系统分解到一个一个的模块。模块化开发的优点:代码复用,让我们更方便地进行代码管理、同时也便于后面代码的修改和维护。一个单独的文件就是一个模块,是一个单独的作用域,只向外暴露特定的变量和函数。

js模块化总结

在很长的一段前端历史里,是不存在打包这个说法的。那个时候页面基本是纯静态的或者服务端输出的, 没有 AJAX,也没有 jQuery。Google 推出 Gmail 的时候(2004 年),XMLHttpRequest, 也就是我们俗称的 AJAX被拾起的时候

AMD 模块化最佳实践

AMD 是 RequireJS 给出的模块加载方案。 支持递归依赖解析、模块异步加载,夜兼容 CommonJS 可以在 Node.js 里用。 虽然目前已经不再流行,很多站点更倾向于编写 ES Modules 并直接 Webpack 打包, 但 AMD 是完整的

ES6 模块化和 .vue组件的应用举例

CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。export通过接口,输出的是同一个值。不同的脚本加载这个接口,得到的都是同样的实例。

Js模块化方案总结

本文包含两部分,第一部分通过简明的描述介绍什么是 CommonJS、AMD、CMD、UMD、ES Module 以及它们的常见用法,第二部分则根据实际问题指出在正常的 webpack 构建过程中该如何指定打包配置中的模块化参数。

css模块化方案

这篇文章主要介绍了css模块化方案,css的模块化方案可能和js的一样多,下面简单介绍几种主要的模块方案,非常具有实用价值,需要的小伙伴可以参考下。css的模块化方案可能和js的一样多,下面简单介绍几种主要的模块方案

理解JS 模块化

在模块化规范形成之前,JS开发者使用Module设计模式来解决JS全局作用域的污染问题。Module模式最初被定义为一种在传统软件工程中为类提供私有和公有封装的方法。在JavaScript中,Module模式使用匿名函数自调用 (闭包)来封装

前端模块化

众所周知,早期 JavaScript 原生并不支持模块化,直到 2015 年,TC39 发布 ES6,其中有一个规范就是 ES modules(为了方便表述,后面统一简称 ESM)。但是在 ES6 规范提出前,就已经存在了一些模块化方案

ES6与 CommonJS 模块化的区别

CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。ES6 Modules 的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。

前端模块化:CommonJS,AMD,CMD,ES6

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

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!