Skip to content

简谈常见库的模块化封装 #8

@ilcherry

Description

@ilcherry

模块是什么?

模块: 指能够单独命名并独立地完成一定功能的程序语句集合(即程序代码和数据结构的集合体)

模块的优点

  • 可维护性 根据定义可知模块是独立的,一个设计良好的模块会让外面的代码对自己的依赖越少越好,这样自己就可以独立去更新和改进。当模块与其他代码解耦时,更新单个模块更容易的多;
  • 命名空间 在 JavaScript 中,顶级函数范围之外的变量是全局变量(意味着每个人都可以访问它们)。因此,
    普遍存在"命名空间污染",其中完全不相关的代码共享全局变量;
    使用模块化开发来封装变量,可以避免污染全局环境。
  • 可重用性 对于公共代码,书写一份,通过模块引入的方式,避免重复的代码

执行环境

我们常接触的执行环境有浏览器端和 Node.js 端。执行环境的不同会造成模块运行方式不同。主要有同步模块加载和异步模块加载方式。

UMD

UMD, 全称 Universal Module Definition, 即通用模块规范。
同时支持 CommonJS 和 amd 风格,也支持非模块化在浏览器端运行。
大多数库均采用 UMD 规范。下面分析 underscore.js 的 UMD 写法。

// underscore.js v1.9.2

(function() {
  var root =
    (typeof self == "object" && self.self === self && self) ||
    (typeof global == "object" && global.global === global && global) ||
    this ||
    {};

  if (typeof exports != "undefined" && !exports.nodeType) {
    // 支持 CommonJS 方式导出
    if (typeof module != "undefined" && !module.nodeType && module.exports) {
      exports = module.exports = _;
    }
    exports._ = _;
  } else {
    // 暴露到全局
    root._ = _;
  }

  // some code

  /* 
  支持 AMD 方式导出
  */
  if (typeof define == "function" && define.amd) {
    define("underscore", [], function() {
      return _;
    });
  }
})();

简单总结 UMD 规范。

  • 判断环境里有没有 define 函数,如果有,支持 AMD 模块导出;
  • 判断环境里有没有 exports 和 module 对象, 如果有,支持 CommonJS 导出,
  • 如果以上两种情况都不符合,就将其暴露到全局环境中

CommonJS

CommonJS 最开始是 Mozilla 的工程师于 2009 年开始的一个项目,它的目的是让
浏览器之外的 JavaScript (比如服务端或者桌面端) 能够通过模块化的方式来开发
和协作

在 CommonJS 的规范中,每个 Javascript 文件就是一个独立的模块上下文(module context)
在这个上下文中默认创建的属性都是私有的。也就是说,在一个文件定义的变量(还包括函数和类),
都是私有的,对其他文件是不可见的。

需要注意的是,CommonJS 规范的主要适用场景是服务器编程,所有采用同步加载模块的策略。
如果我们依赖 3 个模块,代码会一个一个依次加载它们。

该模块实现方案主要包含 require 与 module 这两个关键字,其允许某个模块对外暴露部分
接口并且由其他模块导入使用。

下面,我们在 Node.js 环境下

// myModule.js

const author = "qinghuanI";

module.exports = { author };


// index.js

const { author } = require("./myModule.js");

console.log(author); // 'qinghuanI'

AMD

AMD 全称 Asynchronous Module Definition, 即异步模块定义,是 RequireJS 在推广过程中对模块定义的规范化产出。
同样的,其规定一个文件就是一个模块,文件名即模块名。

AMD 使用 define 函数定义模块;使用 require 函数引用模块。

define 函数使用方式如下

define(id?, dependencies?, factory);

定义 myModule.js 模块

define(['dependModule'], function(dependModule){
  // do something
});

require 接受两个参数,第一个参数为所依赖的模块标识数组;第二个参数为
依赖模块加载完成后的回调函数。

在 main.js 中引用 myModule 模块

require(['myModule'], function (myModule){
  //do something
});

AMD 推崇依赖前置,需要先异步加载其所需的依赖模块后才会执行
相应回调函数中的代码。

参考链接

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions