JavaScript模块模式示例[关闭]


136

我找不到任何可访问的示例来说明如何将两个(或多个)不同的模块连接在一起一起工作。

因此,我想问一下是否有人有时间编写示例来解释模块如何协同工作。


在过去的四年中,这一切都发生了变化,但是由于热心的过度节制,这些过时的信息将永远存在。这是ES6模块上的MDN页面
bbsimonbb

Answers:


256

为了采用模块化设计模式,您需要首先了解以下概念:

立即调用的函数表达式(IIFE):

(function() {
      // Your code goes here 
}());

您可以通过两种方式使用这些功能。1.函数声明2.函数表达式。

这里使用函数表达式。

什么是名称空间?现在,如果我们将名称空间添加到上面的代码中,那么

var anoyn = (function() {
}());

JS中的闭包是什么?

这意味着,如果我们在任何函数范围内/在另一个函数内部声明任何函数(在JS中,我们可以在另一个函数内部声明一个函数!),则它将始终计入该函数范围。这意味着将始终读取外部函数中的任何变量。它不会读取具有相同名称的全局变量(如果有)。这也是使用模块化设计模式避免命名冲突的目标之一。

var scope = "I am global";
function whatismyscope() {
    var scope = "I am just a local";
    function func() {return scope;}
    return func;
}
whatismyscope()()

现在,我们将应用我上面提到的这三个概念来定义我们的第一个模块化设计模式:

var modularpattern = (function() {
    // your module code goes here
    var sum = 0 ;

    return {
        add:function() {
            sum = sum + 1;
            return sum;
        },
        reset:function() {
            return sum = 0;    
        }  
    }   
}());
alert(modularpattern.add());    // alerts: 1
alert(modularpattern.add());    // alerts: 2
alert(modularpattern.reset());  // alerts: 0

jsfiddle用于上面的代码。

目的是隐藏外界的可变可访问性。

希望这可以帮助。祝好运。


命名伊菲尔会更好吗?出于语义目的和更好的堆栈跟踪?它会改变代码中的任何内容吗?
Jeroen 2014年

2
您的第一个示例(function() { /* Your code goes here */}());实际上是IIFE(立即调用函数表达式),好吧,它是匿名的,因为它没有名称,因此您甚至可以将其称为IIAFE(立即调用匿名函数表达式),有关更多关于IIFE的信息,请访问stackoverflow.com/questions/ 2421911 /…
阿德里安

为什么使用return语句?如果我们省略return {},那么add和reset函数将是公共的,我想他们可以访问局部变量sum了吗?我对吗?
谅解

你的第二个例子看起来像一个对象还是我不对?
原因2015年

4
这没有解决OP的问题。它是对模块模式的描述,而不是多个模块如何按照OP希望一起工作的示例。
Erik Trautman

39

我真的会建议任何进入此主题的人阅读Addy Osmani的免费书籍:

“学习JavaScript设计模式”。

http://addyosmani.com/resources/essentialjsdesignpatterns/book/

当我开始编写更可维护的JavaScript时,这本书极大地帮助了我,我仍然将其用作参考。看一下他不同的模块模式实现,他很好地解释了它们。


我还建议您阅读有关Addin
tfmontague 2014年

1
这与Stoyan Stefanov的“ JavaScript模式”相比如何
JohnMerlino 2014年

4
斯托扬的书更加全面。它不仅涵盖高级模式,而且还更深入地讨论了其他JS最佳实践。
代码Novitiate

1
“学习JavaScript设计模式”的评论amazon.com/product-reviews/1449331815
Adrien Be

3
Stoyan Stefanov 撰写的“ JavaScript模式”评论amazon.com/product-reviews/0596806752。注意:这似乎比“学习JavaScript设计模式”中的内容要好得多
Adrien Be

19

我想通过讨论如何将模块组合到应用程序中来扩展上述答案。我已经在道格·克罗克福德(Doug Crockford)的书中读到了有关此内容的内容,但对于javascript来说,它还是有点神秘。

我来自ac#背景,因此添加了一些我觉得有用的术语。

HTML

您将拥有某种顶级html文件。将其视为您的项目文件会有所帮助。您添加到项目中的每个javascript文件都希望加入该程序,但是不幸的是,您对此没有工具支持(我正在使用IDEA)。

您需要使用如下脚本标签将文件添加到项目中:

        <script type="text/javascript" src="app/native/MasterFile.js" /></script>
        <script type="text/javascript" src="app/native/SomeComponent.js" /></script>

折叠标签似乎会导致事情失败-虽然看起来像xml,但确实有些疯狂的规则!

命名空间文件

MasterFile.js

myAppNamespace = {};

而已。这仅是为了为我们其余的代码添加一个全局变量而存在。您还可以在此处(或在它们自己的文件中)声明嵌套的名称空间。

模组

SomeComponent.js

myAppNamespace.messageCounter= (function(){

    var privateState = 0;

    var incrementCount = function () {
        privateState += 1;
    };

    return function (message) {
        incrementCount();
        //TODO something with the message! 
    }
})();

我们在这里所做的是将消息计数器函数分配给应用程序中的变量。这个函数返回一个我们立即执行的函数。

概念

我认为将SomeComponent的顶行视为声明内容的名称空间会有所帮助。唯一需要注意的是,您的所有名称空间都需要首先出现在其他文件中-它们只是由我们的应用程序变量植根的对象。

目前,我仅对此采取了一些小步骤(我正在从extjs应用程序中重构一些普通的javascript,以便可以对其进行测试),但它看起来非常不错,因为您可以定义一些小的功能单元,而又避免了'this的泥潭'

您还可以使用此样式来定义构造函数,方法是返回一个函数,该函数返回带有函数集合的对象,而不必立即调用它。


6

https://toddmotto.com/mastering-the-module-pattern中,您可以找到完整解释的模式。我要补充一点,关于模块化JavaScript的第二件事是如何在多个文件中构造代码。许多人可能会建议您选择AMD,但是从经验上我可以说,由于大量HTTP请求,您最终会在页面响应缓慢的某个点上失败。解决方法是将您的JavaScript模块(每个文件一个)预编译为遵循CommonJS标准的单个文件。在这里看看示例http://dsheiko.github.io/cjsc/


所有AMD实施还提供了预编译到单个文件中的功能。
I-林廓

1
没错,但是生成的优化文件需要加载程序库(只需使用r.js v2.1.14重新检查它),通常很重。一旦我们编译了代码,我们就不需要解析异步加载的依赖关系,我们也不需要这个库。只需考虑:我们将模块包装到AMD中,这意味着异步。加载,然后将它们编译到一个文件中(不再进行单独加载),但是加载整个库来解决它们(现在有什么多余的地方)。这听起来并不是我的最佳选择。当我们不异步加载时为什么要使用AMD?
德米特里·谢科

与RequireJS相比,almond.js为最终产品代码提供了更小的重量加载程序,但是相对而言,仅发出单个http请求的性能优势远远超过了将加载程序代码添加到模块中的成本,因此,虽然它不是最优的,但是规模要小得多。我认为应该解决这个问题-为什么当浏览器不同步时为什么要保持同步?其实,我的意见是我这两个RequireJS和CommonJS的应该都内置有承诺的实现。
I-林廓

两种格式都是指向CommonJS Modules / 2.0的有效路径,并提供相同的可伸缩性。对我来说-处理CJS Modules / 1.1(这就是CommonJS的意思)要容易得多,代码看起来更干净。
德米特里·谢科

我已经获得了AMD的以下好处:*不仅可以加载JavaScript文件,还可以加载更多内容;*路径别名;好吧,CommonJS Compiler解决了这些问题-它将非JavaScipt / JSON依赖项加载为数据,并可以提供构建配置(包括别名)。它需要构建的唯一缺点。但是如今,无论如何,每个人都为CSS预处理程序构建项目。所以这只是为Grunt / Gulp添加一个额外的任务...
Dmitry Sheiko 2014年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.