技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> JavaScript --> JavaScript模块的前世今生

JavaScript模块的前世今生

浏览:2178次  出处信息

如今JavaScript模块化编程的概念已经普及开来,一提起模块化,大家想到的可能是AMD,CMD,requirejs或seajs。其实还有很多其他的概念。本文将会陈述下JavaScript模块的前世今生。

众所周知,JavaScript由于历史的原因并没有模块的概念,自从ajax带来了web2.0概念后,js代码已经和以前大不相同了,2009年HTML5兴起后,前端代码的行数已经呈现井喷式发展,随着代码量的增加,模块的缺失的缺点日益凸显,Javascript社区做了很多探索。

模块的定义

模块并非js语言独创,显然是借鉴其他语言的,下面是百度百科对模块的定义:

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

从中提炼出几个关键字就是,独立,集合,完成一定功能。

上面的提炼,再从其他语言的实现中借鉴下,总结起来,我们期待的模块有如下特性:

  • 独立性——能够独立完成一个功能,不受外部环境的影像

  • 完整性——完成一个特定功能

  • 集合性——一组语句的集合

  • 依赖性——可以依赖已经存在的模块

  • 被依赖——可以被其他模块依赖

其实我们想要的就是一个独立的模块,并能引用依赖,及被依赖。

C语言的库和头文件(include),java的包(import)。这在其他语言中都是原生支持的特性,在js中却是没有的。

原始写法

如果仅从定义入手,那么一个函数即可成为一个模块(独立,集合,完成一个功能),那我们就先从最原始的探索开始,也许不经意间,我们早已在使用模块了。

//最简单的函数,可以称作一个模块function add(x, y) {return x + y;}

稍微了解点javascript基础的人都知道js中能创建作用域的就是函数(ES6之前),总结下社区的探索,对模块的模拟大概如下:

(function (mod, $, _) {mod.add = ***;mod.sub = ***;}((window.mod = window.mod || {}), jQuery, Underscore));

上面的mod模块不会重复定义,可自由定义依赖。

99%的人思想会止步于此,但这种实现其实并不完美,仍然需要手动维护依赖的顺序。典型的场景就是上面的jquery必须先于我们的代码引入,不然会报引用错误,这显然不是我们想要的。

我在写Painter的时候,曾经手动维护几十个script之间的先后顺序,这种感觉很虐心,最后想加个新script很容易报错。下面介绍的

YUI

前段时间雅虎宣布YUI不再更新了,很是伤感,最早接触模块的概念,当属YUI了,当然不是YUI2了。

YUI3经过全新设计,使用了沙箱模式 + 命名空间的方式,并有了模块的概念。

例如在YUI3中想使用一个模块,需要如下这样:

//使用node模块,node模块会作为参数传入YUI().use('node', function (Y) {///***}

YUI的模块化已经做的很好了,但对于仅想使用模块的人,要引入YUI确实有点太重了。

CMD(Common Module Definition)

说道CMD就不能不提commonjs,提到commonjs就不能不提node

CMD规范参照commonjs中的方式,定义模块的方式如下:

define(function(require, exports, module) {  // The module code goes here});

一个文件就是一个模块,文件名就是模块的名字,使用模块的方法也和commonjs中一致,只需require就好了,模块名字可省略后缀。

//使用event.js模块var ec = require('event');

CMD的典型实现就是seajs,应用的很广泛。

AMD(Asynchronous Module Definition)

[AMD](https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88)是异步模块定义,特别适合在浏览器端使用,其规范和CMD是很像的,AMD规范中定义模块的方式如下:

define(id?, dependencies?, factory);

同CMD一样,一个文件即一个模块,模块的使用方法如下:

define(["beta"], function (beta) {bata.***//调用模块});

AMD主张依赖注入,这点和CMD不同(以来查找)。

AMD也支持已CMD的方式来使用依赖。

AMD的典型实现有requireJSmodJSlodJS

KMD

KMD是kissy中提出来的,是kissy自己的一套模块化方案,具体我也不是很清楚,感兴趣的同学可自行搜索相关资料。

有一次同事@eric曦尧无意说起,KMD的意思是 kill amd and cmd,当时觉得好高打上的名字(/ □ \)。

ES6

ES6带来了语言层面的模块化支持,规范方面见这里,文档方面见这里

我们现在期待的就是ES6规范快点尘埃落定(据说今年夏天),现在还处于草案状态,还有浏览器厂商们的大力支持,还有就是在国内尽快普及开来。

UMD

UMD的全称是Universal Module Definition。和它名字的意思一样,这种规范基本上可以在任何一个模块环境中工作。

一段典型的UMD代码如下所示:

(function (root, factory) {    var Data = factory(root);    if ( typeof define === 'function' && define.amd) {        // AMD        define('data', function() {            return Data;        });    } else if ( typeof exports === 'object') {        // Node.js        module.exports = Data;    } else {        // Browser globals        var _Data = root.Data;                Data.noConflict = function () {            if (root.Data === Data) {                root.Data = _Data;            }                        return Data;        };        root.Data = Data;    }}(this, function (root) {var Data = ...//自己的代码return Data;}));

这是出自data.js中的一部分代码,其原理就是做个判断,不同的环境进行不同的处理。

我已将UMD应用到自己的项目中,瞬间感觉高大上了不少:-)。

总结

比较成气候的模块化方案,当属AMD和CMD,网上关于二者比较的文章甚多,很难评价谁好谁坏,当下开来AMD的使用范围似乎更广些,而CMD的本土化方面做的更好。

这些模块化的探索,使前端工程化成为了可能,可以说没有模块,工程化更无从弹起,本文总结了大家在模块化方面的一些探索,下一篇文章将重点介绍下lodJS(一款基于AMD的模块加载器)的实践和原理。

参考资料


建议继续学习:

  1. 在Apache2.2.XX下安装Mod-myvhost模块    (阅读:11474)
  2. Nginx模块开发入门    (阅读:9587)
  3. 规范自己的JavaScript书写    (阅读:5796)
  4. JavaScript,只有你想不到    (阅读:4941)
  5. nginx模块开发    (阅读:4415)
  6. 我希望我知道的七个JavaScript技巧    (阅读:4304)
  7. JavaScript是Web的汇编语言(一):语义Web已死!    (阅读:4229)
  8. CommonJS 的模块系统,AMD 和 Wrappings, 以及 RequireJS    (阅读:4057)
  9. Javascript的那些事儿    (阅读:3869)
  10. 能说明你的Javascript技术很烂的五个原因    (阅读:3829)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1