今天看requirejs官网的manual,发现了下面这篇好文章,于是花点时间翻译了一下,翻译不好的地方请指正,谢谢!
 
 
模块式编程市一中普遍的JavaScript编程模式。它很好理解,但是有一些高级用法还没被很多人注意到。在这篇文章中,我会回顾一些基本用户,同时包含一些非常有用的高级应用,也包括一个最原始应用。
      
基本应用
 
我们简单过一遍模块化编程。该模式从三年前, YUI的Eric Miraglia在他的博客中第一次提起它,就被开始广泛的认识。 如果已经很熟悉该模式,可以直接跳到“高级应用”部分。
 
匿名闭包
 
这是有一个最基本的构造函数组成,它真的是JavaScript最好的功能。我们只是简单的创建一个匿名函数,然后马上执行它。所有在函数里面的代码将运行在闭包内,这为我们应用程序的生命周期提供私有性和状态。
(function () {
// ... all vars and functions are in this scope only
// still maintains access to all globals
}());
匿名函数由一个()括号包起来。这是因为JavaScript语言认为以function为开头的语句,都是定义函数的语句。添加括号就变成了创建函数表达式。 全局引入 JavaScript有一个叫隐含全局变量的特征。任何时候,一个变量名被使用,编译器会往回遍历作用域链,知道找到这个变量名的var声明语句。如果没找到,则该变量当成全局变量,如果是为它赋值,则会为它创建一个全局变量。这意味着,在匿名函数中,非常容易创建或使用全局变量。不幸的是,这会导致代码非常难管理,因为对于程序员来说,不知道代码中哪个变量是全局变量。 幸运的是,匿名函数提供了一个简单的解决办法,通过传入一个全局的参数到匿名方法来引用它们,这样一来就比引用全局变量更加清晰和快速。下面是这个例子:
(function ($, YAHOO) {
// now have access to globals jQuery (as $) and YAHOO in this code
}(jQuery, YAHOO));
公开模块

有时候我们不只需要使用全局变量,还需要声明他们。我们可以通过你们函数的return value,很容易来公开这些全局变量。这样我们就完成一个基本的模块化设计,下面是完整的代码示例:
var MODULE = (function () {
var my = {},
privateVariable = 1; function privateMethod() {
// ...
} my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
}; return my;
}());
注意到我们这里定义了一个MODULE的全局变量,包含了两个公开属性:一个名为MODULE.moduleMethod方法和
MODULE.moduleProperty属性。另外,通过匿名闭包,还可以维护着一个私有的内部状态。同时,我们还可以使用上面的方法,轻易的引入全局变量。

高级应用

虽然上面的模式能够应付许多使用场景,不过我们可以更深入的了解该默认,来穿建更多强大的,具有扩张性的构件。还需继续上面的模块MODULE,让我们一个个使用。

扩展

目前该模式的一个限制就是,整个模块都必须在一个文件中。任何曾经在大型代码量下工作的人,都知道把代码分开成几个文件的价值。幸运的是,我们有一个很好的办法来扩展模块。首先,我们引入模块,然后继续添加属性,再把它暴露出去。下面是例子,传入的参数是上面的MODULE
var MODULE = (function (my) {
my.anotherMethod = function () {
// added method...
}; return my;
}(MODULE));
为了保持代码一致,我们在MODULE前加上var,虽然可以去掉。上面代码运行后,我们的模块会多出一个公开函数:MODULE.anotherMethod,这个扩展文件同事会维护者它自己私有的内部状态和引入的内容。

松散扩展

虽然我们上面例子要求先初始化模块,然后在扩展模块新的内容,但是并不是非得这样。JavaScript应用程序最后的一个地方,就是可以异步加载脚本文件。我们可以通过松散扩展,创建灵活的,可以已任何顺序加载的,多文件模块。每个文件需要按照下面的代码结构:
var MODULE = (function (my) {
// add capabilities... return my;
}(MODULE || {}));
在这个模式下,var关键字都必须写上。因为这里的会创建模块,如果该模块还未存在。这意味着你可以使用想LABjs这样的工具,异步加载模块文件,而不用阻塞进程。
紧耦合扩展

虽然松散扩展挺好的,但是也存在一些限制。最重要的是,你不能安全的重写模块的属性。同时,在初始化的过程中,你不能使用模块的其它属性(但是你可以在初始化完成后的运行时使用)。紧耦合扩展需要按一定顺序加载,但是它支持重载。下面是一个简单例子(参数还是之前的MODULE):
var MODULE = (function (my) {
var old_moduleMethod = my.moduleMethod; my.moduleMethod = function () {
// method override, has access to old through old_moduleMethod...
}; return my;
}(MODULE));
这里我们重写了MODULE.moduleMethod方法,同时,保留着旧函数的一个引用,以便未来需要。

克隆与继承

var MODULE_TWO = (function (old) {
var my = {},
key; for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
}
} var super_moduleMethod = old.moduleMethod;
my.moduleMethod = function () {
// override method on the clone, access to super through super_moduleMethod
}; return my;
}(MODULE));
这个模式可能是最缺乏灵活性的一个了。它运行一些整齐的组合,但是确牺牲了灵活性。正如上面的代码,对象或者函数的属性不会重复,他们存在同个对象中的两个引用。修改其中一个,同时也会改动另外一个。

跨文件私有状态

才分模块成多个文件的一个最主要的限制是,它们每个文件都维护者自己的私有状态,而且不能访问其它文件的私有状态。这是可以修复的。
下面就是一个使用松散扩展模块,同时可以维护所有扩展的私有状态的例子:

 
var MODULE = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
delete my._private;
delete my._seal;
delete my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
}; // permanent access to _private, _seal, and _unseal return my;
}(MODULE || {}));
 

任何文件都可以设置本地属性_private, 而且它马上就可以从其它文件反问到。一旦这个模块加载完成,应用程序必须调用MODULE._seal(),组织外部环境修改内部的_privaet变量。如果module有添加新的扩展,在程序的生命周期内,人和一个内部函数,任何文件中,在加载文件之前调用_unseal()方法,然后执行完成后再调用_seal()。这个方法是今天上班的时候想出来的,我还没在别的地方看过。我想它是一个很有用的模式,因此值得单独来写这一块内容。

子模块

我们最后一个高级应用其实是最简单的。在很多情况下创建子模块是非常有用的。它就跟创建一个普通的模块一样

MODULE.sub = (function () {
var my = {};
// ...

return my;
}());

虽然这很简单,但是还是值得把它包含进来。子模块由于普通模块的有点,包含扩展功能和私有状态。

总结

大多数的高级应用都可以和其它应用结合一起,从而创建更好的模式。如果一定要我指出一个设计复杂应用程序的组合,
我会合并松散模式,私有状态和子模块。

在这里我没有涉及到性能问题,但是我想在这里说:这些模块化模式性能都很好。他们能很好的压缩,让加快下载代码的时间。
使用松散扩展运行非阻塞并行下载文件,同时也提高下载的速度。初始化时间可能慢于其它方法,但是值得的。运行时应该也不会
有什么问题,因为全局变量被正确的包含进去。而且子模块因为缩短了本地变量的引用链,反而能提高一些速度。

最后,下面是一个子模块的例子,针对于它的父模块(如果不存在则创建),它自己可以动态加载本身。
这里没有包含私有状态,但是包含进来是很简单的。这个模式运行整个复杂的代码结构异步的加载本身以及其子模块。

var UTIL = (function (parent, $) {
var my = parent.ajax = parent.ajax || {};

 

my.get = function (url, params, callback) {
// ok, so I'm cheating a bit :)
return $.getJSON(url, params, callback);
};

 

// etc...

 

return parent;
}(UTIL || {}, jQuery));

 

我希望本文对你有帮助,请留言你们的想法。现在,更好去的编写模块化程序吧!

Reference: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html

深入JavaScript模块化编程的更多相关文章

  1. Javascript模块化编程(三):require.js的用法

    Javascript模块化编程(三):require.js的用法 原文地址:http://www.ruanyifeng.com/blog/2012/11/require_js.html 作者: 阮一峰 ...

  2. Javascript模块化编程(二):AMD规范

    Javascript模块化编程(二):AMD规范   作者: 阮一峰 原文地址:http://www.ruanyifeng.com/blog/2012/10/asynchronous_module_d ...

  3. Javascript模块化编程(一):模块的写法

    Javascript模块化编程(一):模块的写法 作者: 阮一峰 原文链接:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html ...

  4. Javascript模块化编程(二):AMD规范(转)

    这个系列的第一部分介绍了Javascript模块的基本写法,今天介绍如何规范地使用模块. (接上文) 七.模块的规范 先想一想,为什么模块很重要? 因为有了模块,我们就可以更方便地使用别人的代码,想要 ...

  5. Javascript模块化编程(一):模块的写法(转)

    随着网站逐渐变成"互联网应用程序",嵌入网页的Javascript代码越来越庞大,越来越复杂. 网页越来越像桌面程序,需要一个团队分工协作.进度管理.单元测试等等......开发者 ...

  6. Javascript模块化编程(二):AMD规范 作者: 阮一峰

    声明:转载自阮一峰的网络日志 这个系列的第一部分介绍了Javascript模块的基本写法,今天介绍如何规范地使用模块. (接上文) 七.模块的规范 先想一想,为什么模块很重要? 因为有了模块,我们就可 ...

  7. Javascript模块化编程(一):模块的写法 作者: 阮一峰

    声明:转载自阮一峰的网络日志 随着网站逐渐变成"互联网应用程序",嵌入网页的Javascript代码越来越庞大,越来越复杂. 网页越来越像桌面程序,需要一个团队分工协作.进度管理. ...

  8. Javascript模块化编程之路——(require.js)

    转自:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html Javascript模块化编程(一):模块的写法 随着网站逐渐变成&q ...

  9. Javascript模块化编程(一):模块的写法 (转载 学习中。。。。)

    转载地址:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html 阮一峰 大神:http://www.ruanyifeng.com/ ...

  10. Javascript模块化编程(二):AMD规范【转】

    作者: 阮一峰 日期: 2012年10月30日 这个系列的第一部分介绍了Javascript模块的基本写法,今天介绍如何规范地使用模块. (接上文) 七.模块的规范 先想一想,为什么模块很重要? 因为 ...

随机推荐

  1. WERTYU(UVa10082)

    C++ 11 代码如下: #include<iostream> using namespace std; const char s[] = { "`1234567890-=QWE ...

  2. LoadRunner监控Linux的三种方法

    方法一.LR + SiteScope/nmon 方法二.使用rstatd包 1.下载rpc.rstatd-4.0.1.tar.gz 2.解压缩 tar -zxvf rpc.rstatd-4.0.1.t ...

  3. bzoj 1112 treap树

    思路:我们只要check一遍每个长度为k的区间就好啦,对于一个区间来说的最优值显然是中位数,我们显然要动态求 第k大,所以需要一个二叉搜索树,用treap就好啦. #include<bits/s ...

  4. 14:Spark Streaming源码解读之State管理之updateStateByKey和mapWithState解密

    首先简单解释一下)) //要使用updateStateByKey方法,必须设置Checkpoint. ssc.checkpoint("/checkpoint/") val sock ...

  5. 什么是泛型 转载自http://www.blogjava.net/Jack2007/archive/2008/05/05/198566.html

    我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型,但我们没有办法,只能分别写多个方法处理每个数据类型,因为方法的参数类 ...

  6. 【SQL SERVER】T-SQL 字符串前加 N 是什么意思

    比如 select @status = N'stopped' 那么其中的字符串 stopped 前面为什么要加 N 呢?而且我们发现有些地方加 N 与否都没有影响,有些地方又必须加 N. N 在这里表 ...

  7. 深入理解javascript函数系列第一篇

    前面的话 函数对任何一门语言来说都是核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即对象,程序可以随意操控它们.函数可以嵌套在其他函数中 ...

  8. 更换mac电脑后证书过期的解决办法

    http://stackoverflow.com/questions/32821189/xcode-7-error-missing-ios-distribution-signing-identity- ...

  9. [UOJ30]/[CF487E]Tourists

    [UOJ30]/[CF487E]Tourists 题目大意: 一个\(n(n\le10^5)\)个点\(m(m\le10^5)\)条边的无向图,每个点有点权.\(q(q\le10^5)\)次操作,操作 ...

  10. 【洛谷】P1176: 路径计数2【递推】

    P1176 路径计数2 题目描述 一个N×N的网格,你一开始在(1,1),即左上角.每次只能移动到下方相邻的格子或者右方相邻的格子,问到达(N,N),即右下角有多少种方法. 但是这个问题太简单了,所以 ...