【问题标题】:How to structure my javascript/jquery code?如何构建我的 javascript/jquery 代码?
【发布时间】:2009-02-09 15:36:39
【问题描述】:

我正在玩弄一个非常密集的基于 ajax 的 jquery web 应用程序。它已经到了一个地步,我几乎忘记了应该触发什么动作的事件等等。

在更基本的层面上,我有点觉得我的 javascript 结构是错误的。你们如何构建 javascript/jquery 代码、事件处理等,对新手 javascript 开发人员有何建议。

【问题讨论】:

标签: javascript jquery


【解决方案1】:

AMDS!

距离这个问题的第一个答案发布已经有一段时间了,很多事情都发生了变化。 首先,JS 浏览器世界似乎正朝着 AMD(异步模块定义)的代码组织方向发展。

工作方式是将所有代码编写为 AMD 模块,例如:

define('moduleName', ['dependency1', 'dependency2'], function (dependency1, dependency2) {
    /*This function will get triggered only after all dependency modules loaded*/
    var module = {/*whatever module object, can be any JS variable here really*/};
    return module;
});

然后使用 AMD 加载器(如 curl.jsrequire.js 等)加载模块,例如:

curl(
    [
        'myApp/moduleA',
        'myApp/moduleB'
    ],
).then(
    function success (A, B) {
        // load myApp here!
    },
    function failure (ex) {
        alert('myApp didn't load. reason: ' + ex.message);
    }
);

优点是:

  1. 您只需在页面上包含单个 <script> 元素即可加载 AMD 加载程序本身(其中一些非常小)。

  2. 之后所有的 JS 文件都会在异步 NON BLOCKING 中自动获取!时尚,因此更快!

  3. 只有在其依赖项被加载后,必要的模块才会被执行。

  4. 模块化(意味着更易于维护和重用的代码)。

  5. 如果使用得当,全局变量污染可以完全遏制。

老实说,一旦概念在您的脑海中点击,您将永远不会回到原来的方式。

P.S:从 1.7 版开始,jQuery 确实将自己注册为 AMD 模块。

有关 AMDS 的更多信息:

【讨论】:

  • 太棒了,我将在下一个项目中研究这个。非常感谢您后来添加到这个问题。
【解决方案2】:

对于 javascript 代码,我发现 Christian Heilmann 的以下链接不可或缺

我也很喜欢 Peter Michaux here 描述的方法

对于 jQuery,我衷心推荐阅读 Authoring 上的指南,我发现 jQuery plugin patterns 上的这个教程非常好

【讨论】:

  • 我确实喜欢创作链接(我必须感谢你),但我不得不承认我不喜欢 jQuery 插件公开公共方法的方式。我想我只是发现 Christian 暴露单个公共对象或 Paul 的公开返回的方法更清晰易读。
  • Christian 刚刚为我指出了该模块的另一个选项,更优雅:wait-till-i.com/2007/08/22/…
【解决方案3】:

为了控制我的事件,我使用了发布/订阅机制

jQuery.subscribe = function( eventName, obj, method ){
    $(window).bind( eventName, function() {
        obj[method].apply( obj, Array.prototype.slice.call( arguments, 1 ) );
    });
    return jQuery;
}

jQuery.publish = function(eventName){
    $( window ).trigger( eventName, Array.prototype.slice.call( arguments, 1 ) );
    return jQuery;
}

这是一个使用示例

// a couple of objects to work with
var myObj = {
    method1: function( arg ) {
        alert( 'myObj::method1 says: '+arg );
    },
    method2: function( arg1, arg2 ) {
        alert( arg1 );
        //republish
        $.publish( 'anEventNameIMadeUp', arg2 );
    }
}

var myOtherObj = {
    say: function(arg){
        alert('myOtherObj::say says: ' + arg);
    }
}



// you can then have all your event connections in one place

//myObj::method2 is now listening for the 'start' event 
$.subscribe( 'start', myObj, 'method2' );

//myOtherObj::say is now listening for the 'another' event
$.subscribe( 'anotherEvent', myOtherObj, 'say' );

//myObj::method1 is now listening for the 'anEventNameIMadeUp' event
$.subscribe( 'anEventNameIMadeUp', myObj, 'method1' );
//so is myOtherObj::say
$.subscribe( 'anEventNameIMadeUp', myOtherObj, 'say' );


// ok, trigger some events (this could happen anywhere)
$.publish( 'start', 'message1', 'message2' );
$.publish( 'anotherEvent', 'another message' );

【讨论】:

【解决方案4】:

除了模块模式之外,我绝对推荐阅读对象字面量模式;这是一篇很好的文章:

http://ajaxian.com/archives/show-love-to-the-object-literal

【讨论】:

  • 链接好像坏了:(
【解决方案5】:
(function($, window, slice)
{

    $.subscribe = function(eventName, obj, method)
    {
        $(window).bind(eventName, function()
        {
            obj[method].apply(obj, slice.call(arguments, 1));
        });
        return $;
    };

    $.publish = function(eventName)
    {
        $(window).trigger(eventName, slice.call(arguments, 1));
        return jQuery;
    };

})(jQuery, window, Array.prototype.slice);

【讨论】:

  • @Akzhan,请参阅我发布到 @meouw 的 cmets。与内存中的替代方案相比,使用 DOM 事件速度较慢。
【解决方案6】:

要添加到现有答案,这里有一个great post,其中涵盖了基于模块模式构建的更高级技术。

一旦您的 Javascript 代码达到一定大小,您将不可避免地希望通过将其分解为多个文件/模块/子模块来对其进行重构。如果您不确定如何使用模块模式来实现这一点,那么这篇文章是必读的。

【讨论】:

    【解决方案7】:

    我的 js 文件通常遵循类似这样的命名约定:

    • xxx.utility.js
    • mypage.events.js
    • xxx.common.js
    • /lib/
    • /OS-DoNotDistribute/lib/

    在哪里

    • 'mypage' 是 html 的名称, aspx、php 等文件。
    • “xxx”是概念。 (即orders.common.js)
    • 'utility' 表示它是可重复使用的 库脚本(即 ajax.utility.js、controlfader.utility.js)
    • 'common' 是可重用的功能 对于这个应用程序,但不能重复使用 其他项目
    • 'lib' 是任何外部或库脚本的子目录
    • “OS-DoNotDistribute”是一个子目录,用于确保在销售应用时不会分发操作系统许可代码。

    另外,对于 ajax,我对回调函数有一个特殊的命名约定,所以很容易分辨它们是什么。

    我不确定它是否与您正在寻找的内容相近,但希望对您有所帮助。

    【讨论】:

    • 您提到了 ajax 回调函数的特殊命名约定。请详细说明。我使用 Ajax 和一些实用程序文件,这些文件包含应用程序状态和 ajax 调用的包装函数等内容。但是,特别是对于 JQuery,回调需要做不同的事情,除其他外,如果单击按钮,则使用服务器响应执行此操作,如果没有响应,则显示此视图,如果响应则显示该视图并使用传入的响应数据填充该视图。
    • 对不起小子,但我不记得了。那是12年前的事了。我最近没有做太多 js,但老实说,如果我现在要做一个 js 应用程序,我不知道我还会使用多少这些约定。在过去的 12 年中,Node.js 的开发有了显着的发展。我现在想知道是否应该删除这个答案。
    • 没有问题。但请不要删除。我将我的文件夹称为“外部”,并看到了您对“lib”的想法。更有意义。实用程序和我等效的“共享”也是如此。舒尔我应该在其他代码中看到它。但是你的帖子会让我重命名那些更明智的名字:)。我相信其他人也可以从中获得一些收益,即使是从较早的帖子中:)。
    【解决方案8】:

    我真的很喜欢这些文章:

    http://www.virgentech.com/blog/2009/10/building-object-oriented-jquery-plugin.html

    http://stefangabos.ro/jquery/jquery-plugin-boilerplate-revisited/

    他们帮助我了解 Telerik 如何为 asp.net mvc 创建扩展。

    【讨论】:

      【解决方案9】:

      我喜欢 AMD 的想法(请参阅 nix's answer)。

      但我通常会将所有 JS 文件编译成一个 JS 文件。 在这种情况下,不需要异步部分。所以我写了一个小“Infile Module Loader”。

      这里是:https://codereview.stackexchange.com/questions/14530/a-little-infile-amd

      【讨论】:

        【解决方案10】:

        我们可以在我们的 javascript-jquery 应用程序中使用 mvc 模式。 (Backbone.js、knockout.js vs....)是我们可以用来实现这一目标的成熟库。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-31
          • 1970-01-01
          • 2021-09-29
          • 2015-10-22
          相关资源
          最近更新 更多