关于JavaScript中代码组织的公认最佳实践

JavaScript

泡芙阿飞斯丁

2020-03-12

随着jQuery之类的JavaScript框架使客户端Web应用程序变得更丰富,更实用,我开始注意到一个问题...

您如何将其组织起来?

  • 将所有处理程序放在一个位置并为所有事件编写函数?
  • 创建函数/类来包装所有功能?
  • 写得像疯了似的,只是希望它能达到最佳效果?
  • 放弃并获得新的职业?

我提到了jQuery,但实际上实际上是任何JavaScript代码。我发现随着线的堆积开始,管理脚本文件或查找所需内容变得越来越困难。我发现的最大问题可能是做同一件事的方法太多,很难知道哪种是当前公认的最佳实践。

关于保持.js文件与应用程序其余部分一样整洁的最佳方法,是否有任何一般性建议还是这仅仅是IDE的问题?有更好的选择吗?


编辑

这个问题的目的是更多关于代码组织而不是文件组织。有一些非常好的合并文件或拆分内容的示例。

我的问题是:组织实际代码的当前公认的最佳实践方法是什么?与页面元素进行交互并创建互不冲突的可重用代码的方式,甚至是推荐的方式?

有些人列出了名称空间,这是一个好主意。还有哪些其他方式,更具体地说是处理页面上的元素并使代码井井有条和整洁?

第1019篇《关于JavaScript中代码组织的公认最佳实践》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

19个回答
番长斯丁Itachi 2020.03.12

延迟加载您需要的代码。Google使用其google.loader执行类似的操作

Near路易小胖 2020.03.12

您没有提及服务器端语言是什么。或者,更重要的是,您在服务器端使用什么框架(如果有)。

IME,我将事情组织在服务器端,然后全部放到网页上。该框架的任务不仅是组织每个页面必须加载的JS,而且还组织与生成的标记一起使用的JS片段。通常您不希望发出这样的片段不止一次-这就是为什么将它们抽象到该代码的框架中以解决该问题的原因。:-)

对于必须发出自己的JS的结束页,我通常会发现所生成的标记中包含逻辑结构。这样的本地化JS通常可以在这种结构的开始和/或结束处进行组装。

请注意,这些都不会让您免于编写有效的JavaScript!:-)

猪猪前端 2020.03.12

您的问题是去年年底困扰我的一个问题。区别在于-将代码交给从未听说过私有和公共方法的新开发人员。我必须构建一些简单的东西。

最终结果是一个很小的框架(大约1KB),该框架将对象文字转换为jQuery。语法在视觉上更易于扫描,如果您的js变得非常大,则可以编写可重用的查询来查找诸如使用的选择器,加载的文件,相关函数等内容。

在这里发布一个小框架是不切实际的,因此我写了一个带有示例博客文章(我的第一个。那是一次冒险!)。欢迎您来看看。

对于这里有几分钟要检查的其他所有人,我非常感谢您的反馈!

建议使用FireFox,因为它支持对象查询示例的toSource()。

干杯!

亚当

JimProL 2020.03.12

对于JavaScript组织,一直在使用以下内容

  1. 您所有JavaScript的文件夹
  2. 页面级javascript获取与页面名称相同的自己的文件。ProductDetail.aspx将是ProductDetail.js
  3. 在库文件的javascript文件夹中,我有一个lib文件夹
  4. 将相关的库函数放在要在整个应用程序中使用的lib文件夹中。
  5. Ajax是我移出javascript文件夹并获得其自己的文件夹的唯一javascript。然后我添加两个子文件夹客户端和服务器
  6. 客户端文件夹获取所有.js文件,而服务器文件夹获取所有服务器端文件。
十三老丝 2020.03.12

我在用这个小东西。它为JS和HTML模板提供了“ include”指令。它彻底消除了混乱。

https://github.com/gaperton/include.js/

$.include({
    html: "my_template.html" // include template from file...
})
.define( function( _ ){ // define module...
    _.exports = function widget( $this, a_data, a_events ){ // exporting function...
        _.html.renderTo( $this, a_data ); // which expands template inside of $this.

        $this.find( "#ok").click( a_events.on_click ); // throw event up to the caller...
        $this.find( "#refresh").click( function(){
            widget( $this, a_data, a_events ); // ...and update ourself. Yep, in that easy way.
        });
    }
});
StafanItachi 2020.03.12

几天前,37Signals的家伙发布了一个RTE控件,但有所不同他们创建了一个库,该库使用某种预处理程序命令捆绑javascript文件。

自从分离我的JS文件以来,我一直在使用它,然后最后将它们合并为一个。这样,我就可以分离出问题,最后只有一个文件通过管道(压缩后,不少)。

在模板中,检查您是否处于开发模式,并包括单独的文件,如果在生产中,则包括最后一个文件(您必须自己“构建”)。

宝儿小哥小卤蛋 2020.03.12

我使用Dojo的包管理dojo.requiredojo.provide)和类系统(dojo.declare它还允许简单的多重继承)将我的所有类/小组件模块化到单独的文件中。这不仅可以使您的代码井井有条,而且还可以让您轻松/及时地加载类/小部件。

神奇小小 2020.03.12

在我的上一个项目-Viajeros.com中,我结合了多种技术。我不知道如何组织网络应用程序-Viajeros是一个为旅行者提供了明确定义区域的社交网站,因此很容易将每个区域的代码分开。

我根据站点部分使用名称空间模拟和模块的延迟加载。在每次加载页面时,我都声明一个“ vjr”对象,并始终向其加载一组通用函数(vjr.base.js)。然后,每个HTML页面都通过一个简单的决定来决定需要哪些模块:

vjr.Required = ["vjr.gallery", "vjr.comments", "vjr.favorites"];

Vjr.base.js从服务器获取每个压缩文件并执行它们。

vjr.include(vjr.Required);
vjr.include = function(moduleList) {
  if (!moduleList) return false;
  for (var i = 0; i < moduleList.length; i++) {
    if (moduleList[i]) {
      $.ajax({
        type: "GET", url: vjr.module2fileName(moduleList[i]), dataType: "script"
      });
    }
  }
};

每个“模块”都具有以下结构:

vjr.comments = {}

vjr.comments.submitComment = function() { // do stuff }
vjr.comments.validateComment = function() { // do stuff }

// Handlers
vjr.comments.setUpUI = function() {
    // Assign handlers to screen elements
}

vjr.comments.init = function () {
  // initialize stuff
    vjr.comments.setUpUI();
}

$(document).ready(vjr.comments.init);

鉴于我对Javascript的了解有限,我知道必须有更好的方法来管理它,但是到目前为止,它对我们来说非常有用。

LEY乐 2020.03.12

我很惊讶没有人提到MVC框架。我一直在使用Backbone.js对我的代码进行模块化和解耦,这是非常宝贵的。

这些框架很多,其中大多数也很小。我个人的观点是,如果您不只是为华丽的UI内容编写几行jQuery,或者想要一个丰富的Ajax应用程序,那么MVC框架将使您的生活变得更加轻松。

米亚ItachiL 2020.03.12

我为我真正不需要在屏幕上实例化多次的每件事创建单例,为其他所有事项创建类。所有这些都放在同一文件的同一名称空间中。一切都已注释,并使用UML状态图进行设计。JavaScript代码不含html,因此没有内联JavaScript,我倾向于使用jquery来最大程度地减少跨浏览器问题。

卡卡西Near 2020.03.12

我的老板仍在谈论编写模块化代码(C语言)的时代,并抱怨如今的代码多么糟糕!据说程序员可以在任何框架中编写汇编。总有一种克服代码组织的策略。基本的问题是那些将Java脚本视为玩具并且从不尝试学习的人。

就我而言,我使用适当的init_screen()在UI主题或应用程序屏幕的基础上编写js文件。使用正确的ID命名约定,我确保在根元素级别上没有名称空间冲突。在不显眼的window.load()中,我根据顶层ID捆绑事物。

我严格使用Java脚本闭包和模式来隐藏所有私有方法。完成此操作后,再也不会遇到属性/函数定义/变量定义冲突的问题。但是,与团队合作时,通常很难执行相同的严格要求。

村村A小卤蛋 2020.03.12

查看JavasciptMVC

您可以 :

  • 将您的代码分为模型,视图和控制器层。

  • 将所有代码压缩到一个生产文件中

  • 自动生成代码

  • 创建并运行单元测试

  • 还有更多...

最棒的是,它使用jQuery,因此您也可以利用其他jQuery插件。

Itachi猪猪猪猪 2020.03.12

Dojo从第一天开始就有模块系统。实际上,它被认为是Dojo的基石,Dojo将所有这些粘合在一起:

使用模块Dojo可实现以下目标:

  • Dojo代码和自定义代码(dojo.declare())的命名空间-不会污染全局空间,不会与其他库共存,并且不会与用户的非Dojo感知代码共存。
  • 按名称(dojo.require()同步或异步加载模块
  • 通过分析模块依赖关系来创建单个文件或一组相互依赖的文件(所谓的图层)以仅包含您的Web应用程序需要的内容,从而进行自定义构建。定制构建还可以包括Dojo模块和客户提供的模块。
  • 基于CDN的透明访问Dojo和用户代码。AOL和Google都以这种方式携带Dojo,但是一些客户也为他们的自定义Web应用程序这样做。
Green猿古一 2020.03.12

在上一份工作中,我能够成功地将Javascript模块模式应用于Ext JS应用程序。它提供了一种创建精美封装代码的简单方法。

十三斯丁Jim 2020.03.12

遵循良好的OO设计原则和设计模式对使代码易于维护和理解大有帮助。但是我最近发现的最好的事情之一就是信号和广告位,也就是发布/订阅。看一下http://markdotmeyer.blogspot.com/2008/09/jquery-publish-subscribe.html, 了解一个简单的jQuery实现。

这个想法已在其他用于GUI开发的语言中很好地使用。当代码中某处发生重大事件时,您将发布一个全局综合事件,其他对象中的其他方法可能会订阅该事件。这样可以很好地分离物体。

我认为Dojo(和Prototype?)具有此技术的内置版本。

另请参阅什么是信号和插槽?

ProTom 2020.03.12

代码组织要求采用约定和文档标准:
1.物理文件的命名空间代码;

Exc = {};


2.在这些名称空间javascript中对类进行分组;
3.设置用于表示现实世界对象的原型或相关函数或类;

Exc = {};
Exc.ui = {};
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};
Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    ...
};


4.设置约定以改进代码。例如,将其所有内部功能或方法分组在对象类型的class属性中。

Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    this.internal = {
        widthEstimates: function (tips) {
            ...
        }
        formatTips: function () {
            ...
        }
    };
    ...
};


5.创建名称空间,类,方法和变量的文档。必要时还讨论一些代码(一些FI和Fors,它们通常实现代码的重要逻辑)。

/**
  * Namespace <i> Example </i> created to group other namespaces of the "Example".  
  */
Exc = {};
/**
  * Namespace <i> ui </i> created with the aim of grouping namespaces user interface.
  */
Exc.ui = {};

/**
  * Class <i> maskdInput </i> used to add an input HTML formatting capabilities and validation of data and information.
  * @ Param {String} mask - mask validation of input data.
  */
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};

/**
  * Class <i> domTips </i> used to add an HTML element the ability to present tips and information about its function or rule input etc..
  * @ Param {String} id - id of the HTML element.
  * @ Param {String} tips - tips on the element that will appear when the mouse is over the element whose identifier is id <i> </i>.
  */
  Exc.ui.domTips = function (id, tips) {
    this.domID = id;
    this.tips = tips;
    ...
};


这些只是一些技巧,但这对组织代码有很大帮助。记住,您必须有纪律才能成功!

宝儿理查德 2020.03.12

您可以将脚本分解为单独的文件进行开发,然后创建一个“发行”版本,在其中将它们全部塞入并运行YUI Compressor或类似的东西。

路易老丝 2020.03.12

如果javascript内置了命名空间,那就更好了,但是我发现组织Dustin Diaz这样的事情对我有很大帮助。

var DED = (function() {

    var private_var;

    function private_method()
    {
        // do stuff here
    }

    return {
        method_1 : function()
            {
                // do stuff here
            },
        method_2 : function()
            {
                // do stuff here
            }
    };
})();

我将不同的“命名空间”(有时将各个类)放在单独的文件中。通常,我从一个文件开始,随着类或命名空间变得足够大以保证它,我将其分离到自己的文件中。使用工具组合所有文件进行生产也是一个好主意。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android