Javascript模块化编程的详细解释

模块化编程是一种非常常见的Javascript编程模型,它通常使代码更易于理解,但有许多优秀的实践并不广为人知。

基础



让我们从Eric Miraglia的一些模块化设计模式的简要概述开始(YUI的开发者)首次发表博客描述模块化模式三年前,如果你已经用这些模块化的模式很熟悉,你可以跳过这部分直接从高级模式开始阅读。

匿名闭包

这是一个基本的结构,使一切成为可能,也是Javascript的最佳特征。我们可以简单的创建一个匿名函数并立即执行。所有的代码将运行在这个功能和生活在一个私有化的封闭,这足以使这些闭包变量贯穿我们整个生活中的应用周期。

复制代码代码如下所示:

(函数(){())

所有的变量和函数 / /…仅在此范围内

保持访问所有的全局变量 / /

}();



注重包裹匿名函数的最外层的括号。因为Javascript的语言特性,为圆括号是必要的。声明,从关键词的作用在JS永远被视为一个功能健全的模式。将这个代码括号允许翻译,知道这是一个函数表达式。

全局变量导入

Javascript有一种称为隐式全局变量。不管在哪一个变量名时,解释器将反向基于作用域链的变量var声明。如果变量声明语句中不难发现,然后变为一个全局变量,如果变量是一个句子中使用赋值语句和变量不存在,一个全局变量将被创建,这意味着它很容易使用或匿名闭包创建全局变量。不幸的是,这是非常难以维持的原因写的代码,因为人们的直观感受,它是不明确的,变量是全局的。

幸运的是,我们的匿名函数提供了一个简单的替代方案,只要将全局变量作为参数传递给我们的匿名函数,就可以得到比隐式全局变量更清晰和更快的代码:

复制代码代码如下所示:

($,函数,雅虎){

访问全局变量jQuery /现在(美元),这个代码雅虎

}(jQuery,雅虎);



模块的出口

有时您不仅希望使用全局变量,还希望声明它们为重复使用。我们可以通过导出这些函数轻松地完成这些操作,通过匿名函数的返回值:

复制代码代码如下所示:

var模块=(函数(){())

var,

privatevariable = 1;

功能privatemethod(){



}

my.moduleproperty = 1;

my.modulemethod =函数(){

/ /…

};

我回;

}();



注意,我们已经宣布了全球模块调用的模块,它有2个公共属性:一种称为module.modulemethod和变量称为module.moduleproperty.in之外,它维护了一个私人的,一个匿名函数内置状态关闭。同时,我们可以很容易地导入所需的全局变量和使用这种模块化的模式,我们学会了早。

推进模式

上述部分所描述的基础足以应付许多情况。现在我们可以进一步开发这种模块化模式,并创建更强大、更可扩展的结构,我们从模块模块开始,并逐一介绍这些高级模式。

放大模式

整个模块必须在文件的模块化模式的限制。任何人参加一个大型的项目将了解JS的价值分裂成多个文件。幸运的是,我们有一个伟大的放大模块实现。首先,我们导入一个模块,添加属性,然后出口。以下是一个放大它从原来的模块:

复制代码代码如下所示:

var模块=(函数(我){)

my.anothermethod =函数(){

添加的方法…

};

我回;

}(模块);



我们使用var关键字来保证一致性,虽然这是没有必要在这里。这段代码被执行后,我们有了一个新的公共模块的方法称为module.anothermethod.this放大文件也保持自己的私人建造的国家进口的对象。

宽的放大模式

上面的示例首先需要初始化模块,然后通过扩展模块执行模块。当然,有时这可能是不必要的。一个Javascript应用程序可以提高性能,最好的事情是脚本的异步执行。我们可以创建灵活的多模块,让他们可以加载任何顺序在一个宽的放大模式。每个文件需要按以下结构组织:

复制代码代码如下所示:

var模块=(函数(我){)

添加 / 功能…

我回;

(模块)| | } { });



在这个模式中,VaR的表达是必要的。注意,如果模块未被初始化,这import语句将创建模块。这意味着你可以使用这样的工具,labjs加载所有的模块文件并行无阻。

紧放大模式

宽放大模式很好,但它也会带来一些限制你的模块。最重要的是,你不能安全地覆盖组件的属性。你不能使用其他文件中的属性初始化时(但你可以使用它,当你运行它)。紧放大模式包含一个加载序列允许重写属性。下面是一个简单的例子(扩大我们原有的模块):

复制代码代码如下所示:

var模块=(函数(我){)

无功old_modulemethod = my.modulemethod;

my.modulemethod =函数(){

/ /访问方法重写,老通过old_modulemethod…

};

我回;

}(模块);



我们盖在上面的例子module.modulemethod的实施,但在需要的时候,你可以保持原来的引用方法。

克隆和遗传

复制代码代码如下所示:

无功module_two =(功能(旧){

var,

关键;

对于(键在旧){

如果(old.hasownproperty(关键)){

我的{旧};

}

}

无功super_modulemethod = old.modulemethod;

my.modulemethod =函数(){

在 / /重写clone方法,通过super_modulemethod获得超

};

我回;

}(模块);



这种模式可能是一个最灵活的选项,并让代码整洁,但它是灵活性为代价的改变。正如我上面写的,如果一个属性是一个对象或函数,它将不会被复制,但将成为对象或函数的第二参考。其中一个会在同一时间被修改,和其他同时修改。这可以通过递归克隆的方法解决,但功能克隆可能不会解决,也许eval可以解决。因此,在这篇文章中,我讲这个方法只考虑到文章的完整性。

交叉文件私有变量

将模块划分为多个文件存在一个主要的限制:每个文件都维护自己的私有变量,不能访问其他文件的私有变量。但是这是一个可以解决的问题:

复制代码代码如下所示:

var模块=(函数(我){)

无功_private =我。_private =我。_private { } | |,

_seal =我。_seal =我。_seal(功能){ | |

我_private删除;

我_seal删除;

我_unseal删除;

},

_unseal =我。_unseal =我。_unseal(功能){ | |

我_private = _private;

我_seal = _seal;

我_unseal = _unseal;

};

访问 / /永久_private,_seal,_unseal

我回;

(模块)| | } { });



所有的文件都可以在各自的_private变量的性质,它明白,它可以被其他文件访问。一旦模块被加载,应用程序可以调用模块。_seal()防止外部调用内部_private.if这个模块需要重新放大,任何文件的内部方法可以调用_unseal()之前加载新的文件,然后调用_seal()新文件被执行后再说。我现在使用这个模式,我还没有看到有任何其他地方。我认为这是一个非常有用的模型,它是值得写在模型本身的文章。

子模块

我们的最后一步的模式是明显的,简单的,有许多优秀的实例创建一个模块。这就像创建一个通用模块。

复制代码代码如下所示:

module.sub =(功能){

var;

/ /…

我回;

}();



虽然看起来很简单,但我认为值得一提的是,子模块具有所有通用模块的先进优势,包括放大模式和私有化状态。

结论



大多数高级模式可以组合起来创建更有用的模式。如果我真的想推荐一个模块化模式来设计复杂的应用程序,我会选择将宽放大模式、私有变量和子模块结合起来。

我还没有考虑这些模型的性能,但我宁愿把它变成一个简单的想法:如果一个模块化模式具有良好的性能,它可以最小化,使这个脚本文件的下载速度更快,使用宽放大模式允许简单的非阻塞并行下载,这将加快下载速度,初始化的时间可能比其他方法稍慢,但它是值得的平衡。只要全局变量是进口的准确,运行性能不受影响,并可能有更快的运行速度在子模块通过缩短与私有变量的引用链。

作为结束,这是一个模块,动态加载到其母模块的一个例子(如果父母不存在,它是创造的)。为了简单起见,我已经取消了私有的变量,当然,这是非常简单的添加私有变量。这种编程模式允许一个完整的层次结构复杂的代码库来完成并行加载的模块。

复制代码代码如下所示:

VaR工具=(功能(父母,$){

我parent.ajax = parent.ajax var = {} | |;

my.get =功能(URL参数,回调){

所以我作弊了。

返回。getJSON(URL参数,回调);

};

等…

回报父母;

(利用| | { } },jQuery));



本文总结了当前Javascript模块化编程的最佳实践,并解释了如何将其应用到实践中,虽然这不是一门初级课程,但您可以稍微理解Javascript的基本语法。