简介
在很久以前,js只是简略的作为浏览器的交互操作而存在,个别都是十分短小的脚本,所以都是独立存在的。
然而随着古代浏览器的倒退,特地是nodejs的呈现,js能够做的事件变得越来越多也越来越简单。于是咱们就须要模块零碎来组织不同用处的脚本,进行逻辑的辨别和援用。
明天将会给大家介绍一下js中的模块零碎。
CommonJS和Nodejs
CommonJS是由Mozilla公司在2009年1月份提出来了。没错,就是那个firfox的公司。
最后的名字叫做ServerJS,在2009年8月的时候为了示意这个规范的通用性,改名为CommonJS。
CommonJS最次要的利用就是服务端的nodejs了。浏览器端是不间接反对CommonJS的,如果要在浏览器端应用,则须要进行转换。
CommonJS应用require()来引入模块,应用module.exports来导出模块。
咱们看一个CommonJS的例子:
require("module"); require("../file.js"); exports.doStuff = function() {}; module.exports = someValue;
留神,CommonJS是同步加载的。
AMD异步模块加载
AMD的全称是Asynchronous Module Definition 。它提供了一个异步加载模块的模式。
AMD是RequireJS在推广过程中对模块定义的规范化产出。
异步加载的益处就是能够在须要应用模块的时候再进行加载,从而缩小了一次性全副加载的工夫,尤其是在浏览器端,能够晋升用户的体验。
看下AMD加载模块的定义:
define(id?, dependencies?, factory);
AMD是通过define来定义和加载依赖模块的。
其中id示意要定义的模块的名字,dependencies示意这个模块的依赖模块,factory是一个函数,用来初始化模块或者对象。
咱们看一个例子:
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //Or: return require("beta").verb(); } });
这个例子中,咱们定义了一个alpha模块,这个模块须要依赖"require", "exports", "beta"三个模块。
并且在factory中导出了beta模块的verb办法。
define中id和dependencies都不是必须的:
//无id define(["alpha"], function (alpha) { return { verb: function(){ return alpha.verb() + 2; } }; });//无依赖 define({ add: function(x, y){ return x + y; } });
甚至咱们能够在AMD中应用CommonJS:
define(function (require, exports, module) { var a = require('a'), b = require('b'); exports.action = function () {}; });
定义完之后,AMD应用require来加载模块:
require([dependencies], function(){});
第一个参数是依赖模块,第二个参数是回调函数,会在后面的依赖模块都加载结束之后进行调用。加载的模块会以参数模式传入该函数,从而在回调函数外部就能够应用这些模块。
require(["module", "../file"], function(module, file) { /* ... */ });
require加载模块是异步加载的,然而前面的回调函数只会在所有的模块都加载结束之后才运行。
CMD
CMD是SeaJS在推广过程中对模块定义的规范化产出。它的全称是Common Module Definition。
CMD也是应用define来定义模块的,CMD推崇一个文件作为一个模块:
define(id?, deps?, factory)
看起来和AMD的define很相似,都有id,依赖模块和factory。
这里的factory是一个函数,带有三个参数,function(require, exports, module)
咱们能够在factory中通过require来加载须要应用的模块,通过exports来导出对外裸露的模块,module示意的是以后模块。
咱们看一个例子:
// 定义模块 myModule.jsdefine(function(require, exports, module) { var $ = require('jquery.js') $('div').addClass('active');});// 加载模块seajs.use(['myModule.js'], function(my){});
所以总结下AMD和CMD的区别就是,AMD前置要加载的依赖模块,在定义模块的时候就要申明其依赖的模块。
而CMD加载完某个依赖模块后并不执行,只是下载而已,只有在用到的时候才应用require进行执行。
ES modules和古代浏览器
ES6和古代浏览器对模块化的反对是通过import和export来实现的。
首先看下import和export在浏览器中反对的状况:
首先咱们看下怎么应用export导出要裸露的变量或者办法:
export const name = 'square';export function draw(ctx, length, x, y, color) { ctx.fillStyle = color; ctx.fillRect(x, y, length, length); return { length: length, x: x, y: y, color: color };}
基本上,咱们能够应用export导出var, let, const变量或者function甚至class。前提是这些变量或者函数处于top-level。
更简略的方法就是将所有要export的放在一行示意:
export { name, draw, reportArea, reportPerimeter };
export实际上有两种形式,named和default。下面的例子中的export是named格局,因为都有本人的名字。
上面看下怎么应用export导出默认的值:
// export feature declared earlier as defaultexport { myFunction as default };// export individual features as defaultexport default function () { ... } export default class { .. }
named能够导出多个对象,而default只能够导出一个对象。
导出之后,咱们就能够应用import来导入了:
import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
如果导出的时候抉择的是default,那么咱们在import的时候能够应用任何名字:
// file test.jslet k; export default k = 12;// some other fileimport m from './test'; // 因为导出的是default,所以这里咱们能够应用import m来引入console.log(m); // will log 12
咱们能够在一个module中应用import和export从不同的模块中导入,而后在同一个模块中导出,这样第三方程序只须要导入这一个模块即可。
export { default as function1, function2 } from 'bar.js';
下面的export from 等价于:
import { default as function1, function2 } from 'bar.js';export { function1, function2 };
下面的例子中,咱们须要别离import function1 function2才可能应用,实际上,咱们能够应用上面的形式将所有的import作为Module对象的属性:
import * as Module from './modules/module.js';Module.function1()Module.function2()
而后function1,function2就变成了Module的属性,间接应用即可。
在HTML中应用module和要留神的问题
怎么在HTML中引入module呢?咱们有两种形式,第一种是应用src选项:
<script type="module" src="main.js"></script>
第二种间接把module的内容放到script标签中。
<script type="module"> /* JavaScript module code here */</script>
留神,两种script标签的类型都是module。
在应用script来加载module的时候,默认就是defer的,所以不须要显示加上defer属性。
如果你在测试的时候应用file:// 来加载本地文件的话,因为JS模块安全性的要求,很有可能失去一个CORS谬误。
最初,import() 还能够作为函数应用,来动静加载模块:
squareBtn.addEventListener('click', () => { import('./modules/square.js').then((Module) => { let square1 = new Module.Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue'); square1.draw(); square1.reportArea(); square1.reportPerimeter(); })});
本文作者:flydean程序那些事本文链接:http://www.flydean.com/js-modules/
本文起源:flydean的博客
欢送关注我的公众号:「程序那些事」最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!