前端常用4种模块化方案总结
栏目: JavaScript · 发布时间: 5年前
内容简介:JS诞生之初面向简单页面开发, 没有模块的概念。后来页面逐渐复杂, 人类构造到 IIFE 立即执行函数来模拟 模块;之前也有雅虎的实践,使用命名空间 作为模块名。最后衍生出 面向各种使用场景 的 JS 模块标准。例如:面向浏览器的 AMD面向Nodejs的 CommonJS
JS诞生之初面向简单页面开发, 没有模块的概念。后来页面逐渐复杂, 人类构造到 IIFE 立即执行函数来模拟 模块;之前也有雅虎的实践,使用命名空间 作为模块名。最后衍生出 面向各种使用场景 的 JS 模块标准。例如:
面向浏览器的 AMD
面向Nodejs的 CommonJS
对于这种分裂状态ES标准也在尽力弥合。 但是目前流行的实践是 UMD模式。
1 AMD
AMD 是requirejs 推广产出的规范,主要用于浏览器环境,通过define和require这两个定义模块、调用模块。
定义模块
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //Or: return require("beta").verb(); } }); // 返回对象的匿名模块 define(["alpha"], function (alpha) { return { verb: function(){ return alpha.verb() + 2; } }; });
调用模块
require(['foo', 'bar'], function ( foo, bar ) { foo.doSomething(); }); define(function (require) { require(['a', 'b'], function (a, b) { //modules a and b are now available for use. }); });
2 commonJS
Node 应用由模块组成,采用 CommonJS 模块规范。
每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
CommonJS 加载模块是同步的,所以只有加载完成才能执行后面的操作。像Node.js主要用于服务器的编程,加载的模块文件一般都已经存在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式,所以CommonJS规范比较适用。但如果是浏览器环境,要从服务器加载模块,这是就必须采用异步模式。所以就有了 AMD CMD 解决方案。
// a.js // 相当于这里还有一行:var exports = module.exports;代码 exports.a = 'Hello world'; // 相当于:module.exports.a = 'Hello world'; // b.js var moduleA = require('./a.js'); console.log(moduleA.a); // 打印出hello world
3 UMD
兼容 AMD 和 commonjs,也兼容 全局变量定义的 通用的模块化规范
(function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD define(['jquery'], factory); } else if (typeof exports === 'object') { // Node, CommonJS-like module.exports = factory(require('jquery')); } else { // Browser globals (root is window) root.returnExports = factory(root.jQuery); } }(this, function ($) { function a(){}; // 私有方法,因为它没被返回 (见下面) function b(){}; // 公共方法,因为被返回了 function c(){}; // 公共方法,因为被返回了 // 暴露公共方法 return { b: b, c: c } }));
4 ES6 Module
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成:export和import。
export命令用于规定模块的对外接口,导出模块暴露的api ;import命令用于输入其他模块提供的功能,引入其他模块。
/** 定义模块 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); }
5 ES6 模块与 CommonJS 模块的差异
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
- ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
- 运行时加载: CommonJS 模块就是对象;即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。
- 编译时加载: ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,import时采用静态命令的形式。即在import时可以指定加载某个输出值,而不是加载整个模块,这种加载称为“编译时加载”。
CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。