JavaScript中的各种模块化规范

前端发展到今天,已经有不少模块化的方案,比如AMD、CMD、UMD、CommonJS等,当然了,还有es6带来的模块系统,这些模块化规范的核心价值都是让 JavaScript 的模块化开发变得简单和自然,今天就来看看这些规范都是啥。

为什么要模块化

在模块化这东西没出来之前,前端脚本引用大概是这样的:

<script src="module1.js"></script>   
<script src="module2.js"></script>   
<script src="libraryA.js"></script>   
<script src="module3.js"></script>   
...   
...   
...

模块把接口暴露到全局对象下(比如window),各个模块可以通过全局对象访问各个依赖的接口,但是也存在一些问题:

1、挂在全局对象下容易产生冲突

2、各个脚本加载的必须严格按照依赖顺序,不然可能就玩不转

3、在一个特别大的项目中,引用的脚本就会特别多,script 标签就会特别多,并且难以维护。比如:

<script src="module1.js"></script>   
<script src="module2.js"></script>   
<script src="module3.js"></script>   
<script src="module4.js"></script>   
<script src="module5.js"></script>   
<script src="module6.js"></script>   
<script src="module7.js"></script>   
<script src="module8.js"></script>   
<script src="module9.js"></script>   
<script src="module10.js"></script>  
<script src="module11.js"></script>   
<script src="module12.js"></script>   
<script src="module13.js"></script>   
<script src="module14.js"></script>   
<script src="module15.js"></script>   
 ...

为了解决这些问题,各种模块化的方案都出来了

CommonJS

这种方式通过一个叫做require的方法,同步加载依赖,然后返导出API供其它模块使用,一个模块可以通过exports或者module.exports导出API。CommonJS规范中,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,在一个文件中定义的变量,都是私有的,对其他文件是不可见的。

require("module");   
require("../file.js");   
exports.doStuff = function() {};   
module.exports = someValue;

服务端Node.js就是用的这种方式。

Well

1、服务端模块可以很好的复用

2、这种风格的模块已经很多了,比如npm上基本上都是这种风格的module

3、简单易用

Less Well

1、加载模块是同步的,所以只有加载完成才能执行后面的操作

2、多个模块不能并行加载

像Node.js主要用于服务器的编程,加载的模块文件一般都已经存在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式,所以CommonJS规范比较适用。但如果是浏览器环境,要从服务器加载模块,这是就必须采用异步模式。所以就有了 AMD 、CMD 的解决方案。

AMD: 异步require

AMD === Asynchronous Module Definition

介于上面的说到的问题,于是浏览器端的异步版本的require应运而生

require(["module", "../file"], function(module, file) { /* ... */ });
define("mymodule", ["dep1", "dep2"], function(d1, d2) {   
  return someExportedValue;   
});

AMD 规范中,define 函数有一个公有属性 define.amd。

Well

1、解决了模块异步加载的问题

2、解决了多个脚本并行加载的问题

Less Well

1、代码太过臃肿,不够优雅,难以阅读和书写

2、但是似乎又是某种解决方案

AMD被使用的最广泛的实现方案无疑就是 require.js 了

CMD表示不服

CMD是SeaJS 在推广过程中对模块定义的规范化产出

CMD 规范中定义了 define 函数有一个公有属性 define.cmd。

CMD 模块中有两种方式提供对外的接口,一种是 exports.MyModule = ...,一种是使用 return 进行返回。

CMD和AMD的区别有以下几点:

1、对于依赖的模块AMD是提前执行,CMD是延迟执行。(require2.0貌似有变化)

2、CMD推崇依赖就近,AMD推崇依赖前置。

//AMD   
define(['./a','./b'], function (a, b) {   

    //依赖一开始就写好   
    a.test();   
    b.test();   
});   

//CMD   
define(function (requie, exports, module) {   

    //依赖可以就近书写   
    var a = require('./a');   
    a.test();   

    if (status) {   
        var b = requie('./b');   
        b.test();   
    }   
});

虽然AMD也支持CMD写法,但依赖前置是官方文档的默认模块定义写法。

推荐一篇文章:SeaJS与RequireJS最大的区别

UMD: 通用模块规范

UMD是AMD和CommonJS两者的结合,AMD 浏览器第一的原则发展,异步加载模块。CommonJS 模块以服务器第一原则发展,同步加载模块,它的模块无需包装。

但是我如果想同时支持两种风格呢?于是通用模块规范(UMD)诞生了。这个模式中加入了当前存在哪种规范的判断,所以能够“通用”,它兼容了AMD和CommonJS,同时还支持老式的“全局”变量规范:

(function (root, factory) {   
    if (typeof define === "function" && define.amd) {   
        // AMD   
        define(["jquery"], factory);   
    } else if (typeof exports === "object") {   
        // Node, CommonJS之类的   
        module.exports = factory(require("jquery"));   
    } else {   
        // 浏览器全局变量(root 即 window)   
        root.returnExports = factory(root.jQuery);   
    }   
}(this, function ($) {   
    //    方法   
    function test(){};    

    //    暴露公共方法   
    return test;   
}));

ES6 modules: 你们都让开,我才是标准

ES6为JavaScript添加了一些语言结构,形成另一个模块系统。

import "jquery";   
export function doStuff() {}   
module "localModule" {}

Well

1、静态分析非常容易

2、未来的标准

Less Well

1、目前的浏览器大都还不兼容,要想使用这种方式的模块系统,貌似只能借助于转译工具了(比如Babel)

2、这种模式的module目前还很少

总结

本文主要是介绍了一下 AMD、CMD等规范,较为笼统,下面的扩展阅读可以更好的帮助你理解模块化以及各个规范。

拓展阅读

模块系统 前端模块化开发的价值 前端模块化开发那点历史 CMD模块定义规范 SeaJS API快速参考 从CommonJS到Sea.js RequireJS和AMD规范 CommonJS规范 Javascript模块化编程 Javascript模块化编程 知乎AMD和CMD的区别有哪些? JavaScript模块化开发 - CommonJS规范 JavaScript模块化开发 - AMD规范

原文发布于微信公众号 - 交互设计前端开发与后端程序设计(interaction_Designer)

原文发表时间:2016-09-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

系统架构之三(业务运营支撑系统)

本人从事过3年的移动业务运营支撑系统开发,行业术语叫做boss系统,后又转入游戏行业进行游戏开发。 现设计一个业务运营支撑系统的架构如下: ? 详细解释各模块如...

410100
来自专栏AI研习社

Github 项目推荐 | 用于训练和测试文本游戏强化学习 Agent 的工具

TextWorld 是一个沙盒环境,用于训练和测试基于文本游戏的强化学习 Agent。

9420
来自专栏匠心独运的博客

过来人的经验,谈谈一致性处理方案—分布式事务(DTS)

传统事务是使用数据库自身的事务属性(ACID),而数据库自身的事务属性是局限于当前实例,不能实现跨库。而对于大型分布式/微服务集群系统中,不仅存在着跨库的事务,...

47240
来自专栏小文博客

OCE – Online Code Editor

16810
来自专栏SAP最佳业务实践

SAP最佳业务实践:ETO–项目装配(240)-4基于SD的更改调整项目

image.png CJ20N基于 SD 的更改调整项目 创建客户订单后,需要基于订单中的更改精调项目。 角色项目经理 后勤®项目系统®项目®项目构造器 1...

49680
来自专栏Java编程技术

分布式事务- TCC编程式模式

严格遵守ACID的分布式事务我们称为刚性事务,而遵循BASE理论(基本可用:在故障出现时保证核心功能可用,软状态:允许中间状态出现,最终一致性:不要求分布式事务...

18530
来自专栏韩伟的专栏

经典的服务器结构概述(中)

. 经典的服务器结构概述(中) 今天将和大家详细探讨分服模型,本文结构如下: ? 1模型描述 分服模型是游戏服务器中最典型,也是历久最悠久的模型。其特征是游...

46870
来自专栏知晓程序

小程序如何关联公众号?| 小程序问答 #42

今天,知晓程序(微信号 zxcx0101)就接着上期,手把手教你如何将小程序与公众号关联起来。

26810
来自专栏程序员互动联盟

【专业技术】Chromium浏览器组件是咋设计出来的?

在文章开始之前,我要叽歪几句,一上来就看chrome的代码,简直晕头转向,摸来摸去摸不着头脑,好不容易看了一点点代码,却宛如瞎子摸象,无法众观全局,下面这篇小文...

36560
来自专栏码字搬砖

sqoop --split-by详解

假设有一张表test,sqoop命令中–split-by ‘id’,-m 10,会发生怎样奇特的事情。首先呢,sqoop会去查表的元数据等等,重点说一下s...

31240

扫码关注云+社区

领取腾讯云代金券