自研模块加载器(一) 模块系统概述与自定义模块规范书写规定

模块系统概述

CommonJs/AMD/CMD/ES6 Modules

 

什么是模块化?

模块化就是把系统分离成独立的功能的方法,需要什么功能,就加载什么功能

当一个系统越来越复杂时候,我们会遇到这些问题

1. 命名冲突

2. 文件依赖

 

使用模块化开发可以避免以上问题,并提升开发效率

1. 可维护性

2. 可复用性

 

在生产角度,模块化是一种生产方式,这种生产方式效率高,维护成本低。

 

 

模块化开发演变

1. 全局函数

早期开发中,将重复的代码封装成函数,将多个函数放在一个文件中。 缺点: 污染全局变量,看不出相互的直接关系

2. 通过对象命名的方式

通过对象命名的形式,从某种程度上减少了变量命名冲突,但是不能从根本上解决。 缺点:内部变量可被外部改写,命名空间越来越长

3. 私有共有成员分离

利用此方式将函数包装成了独立的作用域,私有空间变量函数不会影响全局。 缺点:解决的变量冲突的问题,但是没有解决降低开发复杂度的问题。

 

CommonJS

CommonJS加载是同步的,也就是说加载完成才能执行后面的操作。

Node.js主要用于服务器编程,模块都是存储在本地硬盘中,加载速度快,所以Node.js 采用CommonJS规范。

 

CommonJS规范为三部分: Module(模块标识)、Require(模块引入)、Exports(模块定义)

Module变量在每个模块内部,就代表当前模块

Exports属性是对外接口,用于导出模块的变量和方法

Require()用来加载外部依赖,读取并执行JS, 返回该模块的Exports对象

 

AMD (RequireJS)

AMD也就是异步模块定义。它采用异步的方式加载模块,通过Define的方式定义模块,require方法加载模块。

定义模块:

define([tools], function(){})

如果该模块还依赖其他模块,则第一个参数以数组的形式传入依赖模块,第二个参数为自定义模块

 

AMD模块加载

require(['modules'],callback);

第一个参数 'modules' 为要加载的成员,因为是AMD异步的,所以第二个参数为模块加载完成后的回调

 

CMD (sea.js)

CMD即通用模块定义。CMD是国内发展出来的规范,Sea.js实现来这个规范。

在CMD规范中,一个模块就是一个文件,代码书写如下:

define(function(require, exports, module ) {
})

CMD推崇依赖就近,延迟执行,文件是提前加载好,只有在require的时候才去执行。

define(function(require, exports, module ) {
    var math = require('./math');
    math.add();
})

 

ES6模块化

语法简介,支持异步加载,未来可以成为浏览器和服务器通过的模块化解决方案。

ES6模块的定义:

新增 'import' 和 'export' 两个关键字

export用于暴露模块功能, import 用于引入模块提供的功能

import { foo, obj } from './lib'; // 引入模块功能
foo();//  使用方法



const foo1 = function() {}
//  导出默认 export default foo1;
export { foo1 }

ES6模块运行机制:

ES6 模块是动态引用,如果使用import 从一个模块加载变量(import foo from 'lib'),变量不会被缓存,而是成为一个指向被加载模块的一个引用。 等到脚本执行时,根据只读引用,到那个被加载的模块中取值。

 

 

自定义模块规范(书写约定)

自定义加载器

模块的定义:

1. 约定:所有的Javascript文件都应该用模块的形式来书写,并且一个文件只能包含一个模块;

2. 使用全局函数define来定义模块 define(factory[require,exports,module]));

3. factory函数在调用时,会始终传递三个参数: require,exports和module, 这三个参数在所有的模块代码里可以用

define(function(require, exports, module)) {
  // 模块代码  
})

模块加载器会从factory.tostring()中解析出来当前模块依赖的模块, 它是一个由模块标识组成的数组。

 

exports用来向外提供模块的api || 使用return直接向外提供api

require 函数用来访问其他模块提供的api

module 参数存储模块的元信息(id是模块的唯一标识, deps依赖泪奔 exports对外提供的接口对象)

 

注意:

1. 在模块代码中, 第一个参数必须命名为 require

2. 不要重命名require函数,或在任何作用域中给require重新赋值

3. require的参数值必须是字符串直接量,不能是表达式。

 

posted @ 2020-01-26 15:20  进击的小牛牛  阅读(203)  评论(0编辑  收藏  举报