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


561

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

您如何将其组织起来?

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

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

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


编辑

该问题旨在更多地涉及代码组织而不是文件组织。有一些非常好的合并文件或拆分内容的示例。

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

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


有人究竟是谁花时间谈论代码组织本身,而不是“仅仅”是什么工具,他使用连击和压缩他的JS文件:stackoverflow.com/questions/16736483/...
阿德里安要

Answers:


183

如果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
            }
    };
})();

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


24
我通常将其称为“克罗克福德方式”。从我+1
马特·布里格斯

4
您甚至可以走得更远。请参阅此链接:wait-till-i.com/2007/08/22/...
MKroehnert

4
@MattBriggs否则称为module pattern,它基于IIFE pattern
Adrien Be

您不需要以某种方式导出课程吗?如何从此类模块的外部创建对象?还是createNewSomething()在返回对象中应该有一个方法,以便对象创建仅在模块内进行?嗯...我希望从外部可以看到类(构造函数)。
罗布施(Robsch)2016年

@robsch他的示例不带任何参数,但是大多数都可以。请参阅我的示例以了解通常的操作方式(TypeScript,但99%相同): repl.it/@fatso83/Module-Pattern-in-TypeScript
oligofren

88

我尽量避免在HTML中包含任何JavaScript。所有代码都封装在类中,每个类都在自己的文件中。对于开发,我有单独的<script>标记以包含每个js文件,但是它们被合并到一个较大的程序包中以进行生产,以减少HTTP请求的开销。

通常,每个应用程序都会有一个“ main” js文件。因此,如果我正在编写“调查”应用程序,则将有一个名为“ survey.js”的js文件。这将包含jQuery代码的入口点。我在实例化期间创建jQuery引用,然后将它们作为参数传递到我的对象中。这意味着javascript类是“纯”的,并且不包含对CSS ID或类名的任何引用。

// file: survey.js
$(document).ready(function() {
  var jS = $('#surveycontainer');
  var jB = $('#dimscreencontainer');
  var d = new DimScreen({container: jB});
  var s = new Survey({container: jS, DimScreen: d});
  s.show();
});

我还发现命名约定对可读性很重要。例如:我在所有jQuery实例前添加“ j”。

在上面的示例中,有一个名为DimScreen的类。(假设这使屏幕变暗并弹出一个警告框。)它需要一个div元素,可以将其放大以覆盖屏幕,然后添加一个警告框,因此我传入了一个jQuery对象。jQuery有一个插件概念,但它似乎是有局限性的(例如,实例不是持久性的,无法访问),没有实际的上涨空间。因此DimScreen类将是仅使用jQuery的标准javascript类。

// file: dimscreen.js
function DimScreen(opts) { 
   this.jB = opts.container;
   // ...
}; // need the semi-colon for minimizing!


DimScreen.prototype.draw = function(msg) {
  var me = this;
  me.jB.addClass('fullscreen').append('<div>'+msg+'</div>');
  //...
};

我使用这种方法构建了一些相当复杂的应用程序。


15
我发现将其$用作变量名前缀是一种更常见的做法,但我可能是错的。因此,我猜想,$s = $('...')不是而是jS = $('...')一个优先事项。但是有趣的是,由于匈牙利符号被认为是一种代码味道。奇怪的是,我的一些JavaScript代码约定/首选项与C#/ Java代码约定有何不同。
jamiebarrow

9
@jamie在这种情况下,这不是代码的味道,这恰好是匈牙利语很好的少数几种情况之一。您可能需要阅读此内容
Dan Abramov

3
@DanAbramov感谢您的链接。我真的必须阅读Joel的所有博客,他解释得很好。绝对值得他拥有名声/声誉。从现在起,我将其Systems Hungarian称为代码气味和Apps Hungarian实践:)
jamiebarrow

我想在C#领域中,考虑到这一点,可能也是一篇推广使用的好文章var。大多数反对使用的论据var是您不确定要返回什么的“类型”,但我想该论据应该反对不知道返回什么的“类”。如果您使用的是Apps Hungarian,那么您就不必担心...有趣。
jamiebarrow

3
@Marnen:我明白你的意思了,但这对程序员来说并不是没有用的。$前缀使我想起以后阅读代码时的含义,从而有助于更快地理解。
肖恩

39

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


有时会有不需要的javascript脚本。将这些发送给客户很浪费。我认为仅发送需要的内容是可以的。当然,对于一整天都在使用的Web应用程序(例如Intranet应用程序),最好在第一页加载时一次发送整批。
DOK

2
@DOK编译应包括删除未使用的内容。
aehlke 2010年

还有一种惰性加载的概念,可以尝试减少带宽需求,即先加载初始页面,然后对所需的脚本文件执行异步加载(如对该问题的其他回答所述)。虽然,这可能需要更多请求,但实际上可能用处较小。@DOK,如果将JS缓存,则一个中等的请求可能比几个小的请求更好。
jamiebarrow

27

受以前的文章启发,我制作了一份RakefileWysiHat(由changelog提及的RTE)分发的供应商目录的副本,并进行了一些修改,包括使用JSLint进行代码检查和使用YUI Compressor进行缩小

这个想法是使用Sprockets(来自WysiHat)将多个JavaScript合并到一个文件中,使用JSLint检查合并文件的语法,并在分发之前使用YUI Compressor对其进行最小化。

先决条件

  • Java运行时
  • 红宝石和耙子宝石
  • 您应该知道如何将JAR放入Classpath

现在做

  1. 下载Rhino并将JAR(“ js.jar”)放入您的类路径中
  2. 下载YUI Compressor并将JAR(build / yuicompressor-xyz.jar)放到您的类路径中
  3. 下载WysiHat并将“供应商”目录复制到您的JavaScript项目的根目录
  4. 下载用于Rhino的JSLint,并将其放在“ vendor”目录中

现在,在JavaScript项目的根目录中创建一个名为“ Rakefile”的文件,并向其中添加以下内容:

require 'rake'

ROOT            = File.expand_path(File.dirname(__FILE__))
OUTPUT_MERGED   = "final.js"
OUTPUT_MINIFIED = "final.min.js"

task :default => :check

desc "Merges the JavaScript sources."
task :merge do
  require File.join(ROOT, "vendor", "sprockets")

  environment  = Sprockets::Environment.new(".")
  preprocessor = Sprockets::Preprocessor.new(environment)

  %w(main.js).each do |filename|
    pathname = environment.find(filename)
    preprocessor.require(pathname.source_file)
  end

  output = preprocessor.output_file
  File.open(File.join(ROOT, OUTPUT_MERGED), 'w') { |f| f.write(output) }
end

desc "Check the JavaScript source with JSLint."
task :check => [:merge] do
  jslint_path = File.join(ROOT, "vendor", "jslint.js")

  sh 'java', 'org.mozilla.javascript.tools.shell.Main',
    jslint_path, OUTPUT_MERGED
end

desc "Minifies the JavaScript source."
task :minify => [:merge] do
  sh 'java', 'com.yahoo.platform.yui.compressor.Bootstrap', '-v',
    OUTPUT_MERGED, '-o', OUTPUT_MINIFIED
end

如果正确完成所有操作,则应该能够在控制台中使用以下命令:

  • rake merge -将不同的JavaScript文件合并为一个
  • rake check-检查代码的语法(这是默认任务,因此您只需键入即可rake
  • rake minify -准备您的JS代码的精简版

在源上合并

使用Sprockets,您可以包含(或require)其他JavaScript文件的JavaScript预处理程序。使用以下语法来包含初始文件(名为“ main.js”)中的其他脚本,但您可以在Rakefile中进行更改:

(function() {
//= require "subdir/jsfile.js"
//= require "anotherfile.js"

    // some code that depends on included files
    // note that all included files can be in the same private scope
})();

然后...

查看WysiHat随附的Rakefile,设置自动单元测试。好东西 :)

现在寻找答案

这不能很好地回答原始问题。我知道,对此我感到很抱歉,但是我将其张贴在这里,因为我希望它对其他人整理他们的混乱情况可能有用。

我解决这个问题的方法是尽我所能进行面向对象的建模,并将实现分成不同的文件。然后,处理程序应尽可能短。List单例的示例也是很好的例子。

还有名称空间……那么它们可以被更深的对象结构所模仿。

if (typeof org === 'undefined') {
    var org = {};
}

if (!org.hasOwnProperty('example')) {
    org.example = {};
}

org.example.AnotherObject = function () {
    // constructor body
};

我不是模仿的忠实拥护者,但是如果您有许多想要移出全局范围的对象,这可能会有所帮助。


18

代码组织要求采用约定和文档标准:
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;
    ...
};


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


13

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

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

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

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


我已经在jQuery中做到了。JS具有内置的事件模型,因此您实际上并不需要太多的框架支持。
Marnen Laibow-Koser


11

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

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

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

9

查看JavasciptMVC

您可以 :

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

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

  • 自动生成代码

  • 创建并运行单元测试

  • 还有更多...

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


是的,我使用过jmvc,它非常好-尽管文档可能会更好
meouw 2010年

9

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

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

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


9

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

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


8

“写得像疯了似的,只是希望它能达到最佳效果?”,我看到了一个仅由2个开发人员开发和维护的项目,这是一个包含大量JavaScript代码的大型应用程序。最重要的是,您可以想到的每种可能的jquery函数都有不同的快捷方式。我建议他们将代码组织为插件,因为这相当于类,模块,名称空间...以及整个Universe的jquery。但是事情变得更糟了,现在他们开始编写插件来替换项目中使用的3行代码的每一个组合。我个人认为jQuery是魔鬼,因此不应在具有大量JavaScript的项目中使用jQuery,因为它鼓励您保持懒惰,不要以任何方式考虑组织代码。我宁愿阅读100行javascript,也不愿阅读40行链接的jQuery函数(I' 我不是在开玩笑)。与普遍的看法相反,以名称空间和类的等效形式组织javascript代码非常容易。这就是YUI和Dojo所做的。如果愿意,您可以轻松地自己滚动。我发现YUI的方法更好,更有效。但是,如果您想编写任何有用的东西,通常需要一个支持摘要的好的编辑器来补偿YUI命名约定。


3
对于长链命令,我会同意您的看法,但是jQuery最好的部分之一是它使所有Javascript都脱离HTML。您可以为所有元素设置事件处理程序,而无需“需要”在元素上添加ID或on <whatever>事件。与往常一样,过度使用任何工具都是不好的……
Hugoware

我曾在jQuery中进行过大型,组织良好的项目。我不知道您为什么认为它会妨碍组织。
Marnen Laibow-Koser 2011年

7

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


3
好的评论是关键-很高兴您这么说,所以我不必这样做。我会添加一致的命名约定,某种易于理解的变量和&变量组织策略。函数,正如您提到的,明智地使用类而不是单例。
matt lohkamp

不需要。如果您需要注释,那么您的代码通常可读性不强。努力编写不需要注释的代码。
Marnen Laibow-Koser 2011年

另外,如果您需要UML和状态图,则可能意味着您的体系结构从代码中还不够清楚。投票失败。
Marnen Laibow-Koser

1
@Marnen精心编写的项目中包含了注释,以说明原因,但不一定是原因。该代码已经描述了WHAT,但是通常您需要一些描述WHY的东西。正在投票。
Cypher 2014年

@Cypher编写良好的项目具有足够清晰的代码,您通常可以说出“为什么”,而不仅仅是“什么”。我不信任任何评论来告诉我“为什么”,因为我无法保证它与代码同步。让代码自己记录。
Marnen Laibow-Koser 2014年

6

在我的上一个项目-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);

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


6

以Jquery为中心的NameSpace方式组织代码可能如下所示,并且不会与其他Javascript API(如Prototype,Ext)冲突。

<script src="jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script type="text/javascript">

var AcmeJQ = jQuery.noConflict(true);
var Acme = {fn: function(){}};

(function($){

    Acme.sayHi = function()
    {
        console.log('Hello');
    };

    Acme.sayBye = function()
    {
        console.log('Good Bye');
    };
})(AcmeJQ);

// Usage
//          Acme.sayHi();
// or
// <a href="#" onclick="Acme.sayHi();">Say Hello</a>


</script>

希望这可以帮助。


这让我觉得有点像杂货店。jQuery.fn是指向的指针jQuery.prototype,因为$()实际上返回的是jQuery构造函数的新实例。在jQuery中添加“插件”意味着只需扩展其原型即可。但是您要做的不是那样,并且有更干净的方法可以完成同一件事。
亚当·拉瑟克

我相信他只是在创建静态函数。我记得在jQuery的文档中看到过这样的声明静态函数的方式是可以接受的
Alex Heyd

6

OO + MVC的良好原理肯定会在管理复杂的javascript应用程序方面大有帮助。

基本上,我正在将我的应用程序和JavaScript组织为以下熟悉的设计(从我的桌面编程时代一直到Web 2.0一直存在)

JS OO和MVC

图像上数值的说明:

  1. 代表我的应用程序视图的小部件。这应该是可扩展的,并且可以整齐地分离,从而实现MVC试图实现的良好分离,而不是将我的小部件转换为意大利面条式代码(相当于在Web应用程序中直接将大量Javascript直接放入HTML中)。每个窗口小部件通过侦听其他窗口小部件生成的事件来通过其他组件进行通信,从而减少了窗口小部件之间的强大耦合,而这可能导致无法管理的代码(还记得在脚本标记中向所有指向全局函数的地方添加onclick的日子吗?
  2. 对象模型表示要在小部件中填充的数据,并将它们来回传递给服务器。通过将数据封装到其模型中,应用程序将成为不可知的数据格式。例如:尽管自然地,这些对象模型大部分都在Javascript中进行了序列化和反序列化为JSON,但如果服务器以某种方式使用XML进行通信,则我需要更改的只是更改序列化/反序列化层,而不必更改所有小部件类。 。
  3. 控制器类,用于管理业务逻辑和与服务器的通信以及偶尔的缓存层。该层控制与服务器的通信协议,并将必要的数据放入对象模型中
  4. 类被整齐地包装在它们相应的命名空间中。我敢肯定,我们都知道Java语言中的讨厌全局名称空间会是多么令人讨厌。

过去,我将文件分成自己的js,并使用常规做法在Javascript中创建OO原理。我很快发现的问题是,有多种方法可以编写JS OO,并且不一定所有团队成员都具有相同的方法。随着团队的扩大(在我的情况下,这个团队超过15人),由于没有面向对象Javascript的标准方法,这变得越来越复杂。同时,我不想编写自己的框架并重复一些我确信比我所解决的要聪明的工作。

jQuery非常适合Javascript Framework,而且我喜欢它,但是随着项目的扩大,我显然需要针对我的Web应用程序的其他结构,尤其是为了促进标准化的OO实践。对于我自己,经过几次实验,我发现YUI3 Base和Widget(http://yuilibrary.com/yui/docs/widget/http://yuilibrary.com/yui/docs/base/index.html)基础结构提供了正是我所需要的。我使用它们的原因很少。

  1. 它提供命名空间支持。真正需要OO和整洁的代码组织
  2. 它支持类和对象的概念
  3. 它提供了一种标准化方法,可将实例变量添加到您的类中
  4. 整齐地支持类扩展
  5. 它提供了构造函数和析构函数
  6. 提供渲染和事件绑定
  7. 它具有基本的小部件框架
  8. 现在,每个小部件都能够使用基于事件的标准模型相互通信
  9. 最重要的是,它为所有工程师提供了Java开发的OO标准。

与许多观点相反,我不必在jQuery和YUI3之间进行选择。这两个可以和平共处。虽然YUI3为我的复杂Web应用程序提供了必要的OO模板,但是jQuery仍然为我们的团队提供了易于使用的JS抽象,我们都喜欢并熟悉。

使用YUI3,我已经成功地通过分离将Base扩展为Model的类,将Widget扩展为View的类和不带控制器的类来创建MVC模式,而Controller类正在进行必要的逻辑和服务器端调用。

窗口小部件可以使用基于事件的模型相互通信,并可以基于预定义的界面侦听事件并执行必要的任务。简而言之,将OO + MVC结构放入JS对我来说是一件快乐的事情。

只是免责声明,我不为Yahoo工作!只是一个试图解决原始问题所带来的相同问题的架构师。我认为,如果有人找到等效的OO框架,那么它也会起作用。原则上,这个问题也适用于其他技术。感谢上帝,感谢所有提出OO Principles + MVC的人,使我们的编程日变得更加易于管理。


5

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


3

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

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

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


1
getsprockets.org是直接链接
马特·加德纳

3

创建伪造的类,并确保将所有可以扔到有意义的单独函数中的东西都做到了。另外,请确保添加很多注释,而不要编写意大利面条式的代码,而应将其全部保留在各个部分中。例如,一些胡扯的代码描述了我的理想。显然,在现实生活中,我还编写了许多基本包含其功能的库。

$(function(){
    //Preload header images
    $('a.rollover').preload();

    //Create new datagrid
    var dGrid = datagrid.init({width: 5, url: 'datalist.txt', style: 'aero'});
});

var datagrid = {
    init: function(w, url, style){
        //Rendering code goes here for style / width
        //code etc

        //Fetch data in
        $.get(url, {}, function(data){
            data = data.split('\n');
            for(var i=0; i < data.length; i++){
                //fetching data
            }
        })
    },
    refresh: function(deep){
        //more functions etc.
    }
};


2

我认为这可能与DDD(域驱动设计)有关。我正在处理的应用程序虽然缺少正式的API,但确实通过服务器端代码(类/文件名等)给出了这种提示。为此,我创建了一个顶层对象作为整个问题域的容器。然后,我在需要的地方添加了名称空间:

var App;
(function()
{
    App = new Domain( 'test' );

    function Domain( id )
    {
        this.id = id;
        this.echo = function echo( s )
        {
            alert( s );
        }
        return this;
    }
})();

// separate file
(function(Domain)
{
    Domain.Console = new Console();

    function Console()
    {
        this.Log = function Log( s )
        {
            console.log( s );
        }
        return this;
    }
})(App);

// implementation
App.Console.Log('foo');

2

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

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

非常适合文件组织。我用代码做到这一点。但是最后,我将代码编译为...假设是dll。您也需要使用javascript,否则最终每页需要15个js文件。
10年

每页请求15个JS文件没有错。无论如何,您的浏览器都会缓存它们以供后续请求使用。
Marnen Laibow-Koser 2011年

@ MarnenLaibow-Koser在页面上请求15个JS文件的唯一问题是浏览器一次可以处理多少个HTTP请求。因此,将它们捆绑到一个文件中可使浏览器同时请求其他必要的文件。
iwasrobbed

没错,但是在前几次命中之后,它们将位于浏览器的缓存中,因此它们不需要HTTP连接。
Marnen Laibow-Koser 2011年

2

我在用这个小东西。它为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.
        });
    }
});

2

您可以使用jquery mx(在javascriptMVC中使用),它是一组脚本,允许您使用模型,视图和控制器。我在一个项目中使用了它,并帮助我创建了结构化的javascript,由于压缩,它以最小的脚本大小运行。这是一个控制器示例:

$.Controller.extend('Todos',{
  ".todo mouseover" : function( el, ev ) {
   el.css("backgroundColor","red")
  },
  ".todo mouseout" : function( el, ev ) {
   el.css("backgroundColor","")
  },
  ".create click" : function() {
   this.find("ol").append("<li class='todo'>New Todo</li>"); 
  }
})

new Todos($('#todos'));

如果您对视图和模型部分不感兴趣,则也只能使用jquerymx 的控制器端。


1

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

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

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

对于任何其他需要几分钟才能查看的人,我非常感谢您的反馈!

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

干杯!

亚当


0

我使用了受Ben Nolan的行为启发的自定义脚本(可悲的是,我现在无法找到当前的链接)来存储大多数事件处理程序。例如,这些事件处理程序由元素className或Id触发。例:

Behaviour.register({ 
    'a.delete-post': function(element) {
        element.observe('click', function(event) { ... });
    },

    'a.anotherlink': function(element) {
        element.observe('click', function(event) { ... });
    }

});

除了包含全局行为的Javascript库之外,我喜欢动态地包含大多数Javascript库。我为此使用Zend Framework的headScript()占位符帮助器,但是例如,您也可以使用javascript通过Ajile 快速加载其他脚本


这是您要找的东西吗?koders.com/javascript/…–
DOK,

是的,就是那个!:)似乎链接后面的代码比我受启发的版本新得多。谢谢你的努力!
Aron Rotteveel

0

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

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

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

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


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.