关于javascript:javascript中的模块系统

42次阅读

共计 4198 个字符,预计需要花费 11 分钟才能阅读完成。

简介

在很久以前,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.js
define(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 default
export {myFunction as default};

// export individual features as default
export default function () { ...} 
export default class {..}

named 能够导出多个对象,而 default 只能够导出一个对象。

导出之后,咱们就能够应用 import 来导入了:

import {name, draw, reportArea, reportPerimeter} from './modules/square.js';

如果导出的时候抉择的是 default,那么咱们在 import 的时候能够应用任何名字:

// file test.js
let k; export default k = 12;

// some other file
import 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 的博客

欢送关注我的公众号:「程序那些事」最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

正文完
 0