随着像jQuery这样的JavaScript框架使客户端Web应用程序更丰富,更实用,我开始注意到一个问题......
How in the world do you keep this organized?
-
将所有处理程序放在一个位置并为所有事件编写函数?
-
创建函数/类来包装所有功能?
-
写得像疯了似的,只希望它能做到最好?
-
放弃并开始新的职业生涯?
我提到了jQuery,但它实际上是任何JavaScript代码 . 我发现随着线条的开始堆积起来,管理脚本文件或找到你要找的东西变得更加困难 . 很可能我发现的最大的问题是有很多方法可以做同样的事情,很难知道哪一个是目前普遍接受的最佳实践 .
是否有关于保持 .js 文件与其他应用程序一样漂亮和整洁的最佳方法的一般性建议?或者这仅仅是IDE的问题?那里有更好的选择吗?
EDIT
这个问题旨在更多地关注代码组织而不是文件组织 . 有一些非常好的合并文件或分割内容的例子 .
我的问题是:目前普遍接受的组织实际代码的最佳实践方法是什么?您的方式是什么,甚至是推荐的方式与页面元素交互并创建可互相冲突的可重用代码?
有些人列出了 namespaces 这是一个好主意 . 还有什么其他方法,更具体地说是处理页面上的元素并保持代码整洁有序?
28 回答
几天前,37Signals的球员们,扭曲了 . 他们创建了一个库,使用一种预处理器命令捆绑javascript文件 .
我一直在使用它,因为我将JS文件分开,最后将它们合并为一个 . 这样我可以分离关注点,最后只有一个文件通过管道(gzip,不能少) .
在模板中,检查您是否处于开发模式,并包含单独的文件,如果在 生产环境 中,则包括最后一个(您必须自己“构建”) .
代码组织要求采用约定和文档标准:
1.物理文件的命名空间代码;
2.这些命名空间中的组类javascript;
3.设置原型或相关函数或类来表示现实世界的对象;
4.设置约定以改进代码 . 例如,将其所有内部函数或方法分组到对象类型的类属性中 .
5.制作名称空间,类,方法和变量的文档 . 必要时还讨论一些代码(一些FI和Fors,它们通常实现代码的重要逻辑) .
这些只是一些提示,但这对组织代码有很大帮助 . 记住你必须有纪律才能成功!
您可以将脚本拆分为单独的文件进行开发,然后创建一个"release"版本,将所有文件一起填入并运行YUI Compressor或类似的东西 .
看看JavasciptMVC .
您可以 :
将代码拆分为模型,视图和控制器层 .
将所有代码压缩到单个 生产环境 文件中
自动生成代码
创建并运行单元测试
等等......
最重要的是,它使用jQuery,因此您也可以利用其他jQuery插件 .
我能够在之前的工作中成功地将Javascript Module Pattern应用于Ext JS应用程序 . 它提供了一种创建精美封装代码的简单方法 .
我认为这可能与DDD(域驱动设计)有关 . 我正在处理的应用程序虽然缺少正式的API,但它确实通过服务器端代码(类/文件名等)提供了这样的提示 . 有了这个,我创建了一个顶级对象作为整个问题域的容器;然后,我在需要的地方添加了名称空间:
我的老板仍然谈到他们编写模块化代码(C语言)的时代,并抱怨现在的代码有多糟糕!据说程序员可以在任何框架中编写程序集 . 始终存在一种克服代码组织的策略 . 基本问题是将java脚本视为玩具并且从不尝试学习它的人 .
在我的例子中,我使用适当的init_screen()在UI主题或应用程序屏幕上编写js文件 . 使用正确的id命名约定,我确保根元素级别没有名称空间冲突 . 在不引人注目的window.load()中,我根据顶级id绑定了一些东西 .
我严格使用java脚本闭包和模式来隐藏所有私有方法 . 执行此操作后,从未遇到过属性/函数定义/变量定义冲突的问题 . 但是,在与团队合作时,通常很难强制执行相同的严格要求 .
我尽量避免包括任何带有HTML的JavaScript . 所有代码都封装在类中,每个类都在自己的文件中 . 对于开发,我有单独的<script>标记来包含每个js文件,但是它们会合并到一个更大的包中进行 生产环境 ,以减少HTTP请求的开销 .
通常,我会为每个应用程序提供一个“main”js文件 . 所以,如果我正在写一个“调查”应用程序,我会有一个名为“survey.js”的js文件 . 这将包含jQuery代码的入口点 . 我在实例化期间创建jQuery引用,然后将它们作为参数传递给我的对象 . 这意味着javascript类是“纯粹的”,并且不包含对CSS ID或类名的任何引用 .
我还发现命名约定对于可读性很重要 . 例如:我在所有jQuery实例之前加上'j' .
在上面的示例中,有一个名为DimScreen的类 . (假设这会使屏幕变暗并弹出一个警告框 . )它需要一个div元素,它可以放大以覆盖屏幕,然后添加一个警告框,所以我传入一个jQuery对象 . jQuery有一个插件概念,但似乎有限(例如实例不是持久的,无法访问),没有真正的好处 . 所以DimScreen类将是一个标准的javascript类,恰好使用jQuery .
我使用这种方法构建了一些相当复杂的应用程序 .
我使用 Dojo's package management (
dojo.require
和dojo.provide
)和类系统(dojo.declare
也允许简单的多重继承)将我的所有类/小部件模块化为单独的文件 . 这不仅可以使您的代码保持井井有条,而且还可以让您懒惰/及时加载类/小部件 .我使用了一个自定义脚本,灵感来自Ben Nolan的行为(我无法找到当前的链接,遗憾的是)存储我的大多数事件处理程序 . 例如,这些事件处理程序由元素className或Id触发 . 例:
我喜欢动态包含大多数Javascript库,但包含全局行为的库除外 . 我为此使用了Zend Framework's headScript() placeholder helper,但你也可以使用use javascript to load other scripts on the fly和Ajile .
在我的上一个项目-Viajeros.com-我使用了几种技术的组合 . 我不知道如何组织一个网络应用程序 - Viajeros是一个社交网站,适合那些定义明确的部分的旅行者,所以很容易将每个区域的代码分开 .
我根据站点部分使用名称空间模拟和模块的延迟加载 . 在每个页面加载时,我声明一个“vjr”对象,并始终为它加载一组公共函数(vjr.base.js) . 然后每个HTML页面通过简单的方式决定需要哪些模块:
Vjr.base.js从服务器中获取每一个并执行它们 .
每个“模块”都有这种结构:
鉴于我有限的Javascript知识,我知道必须有更好的方法来管理它,但直到现在它对我们来说都很有用 .
您没有提到您的服务器端语言 . 或者,更有针对性的是,您正在使用的框架 - 如果有的话 - 在服务器端 .
IME,我在服务器端组织一些东西,让它全部转移到网页上 . 该框架的任务不仅是组织每个页面必须加载的JS,还要组织使用生成的标记的JS片段 . 这些片段通常不需要多次发出 - 这就是为什么它们被抽象到该代码的框架中以处理该问题 . :-)
对于必须发出自己的JS的结束页面,我通常会发现生成的标记中存在逻辑结构 . 这种本地化的JS通常可以在这种结构的开始和/或结束时组装 .
请注意,这些都不能免除您编写高效的JavaScript! :-)
我'm surprised no one mentioned MVC frameworks. I'已经使用Backbone.js模块化和解耦我的代码,这是非常宝贵的 .
这里有很多类型的框架,其中大多数都非常小 . 我个人的观点是,如果你要编写的不仅仅是几行jQuery for flashy UI,或者想要一个丰富的Ajax应用程序,MVC框架将使你的生活更轻松 .
对于JavaScript组织一直在使用以下内容
所有javascript的文件夹
页面级别javascript获取其自己的文件,其页面名称相同 . ProductDetail.aspx将是ProductDetail.js
在库文件的javascript文件夹中,我有一个lib文件夹
将相关库函数放在要在整个应用程序中使用的lib文件夹中 .
Ajax是我移动到javascript文件夹之外的唯一一个javascript并获取它自己的文件夹 . 然后我添加两个子文件夹客户端和服务器
Client文件夹获取所有.js文件,而server文件夹获取所有服务器端文件 .
你的问题是去年年底困扰我的问题 . 差异 - 将代码交给那些从未听说过私人和公众的新开发人员方法 . 我必须 Build 简单的东西 .
最终结果是一个小的(大约1KB)框架,它将对象文字转换为jQuery . 语法在视觉上更容易扫描,如果你的js变得非常大,你可以编写可重用的查询来查找使用的选择器,加载的文件,依赖函数等 .
在这里发布一个小框架是不切实际的,所以我写了一个blog post with examples(我的第一个 . 那是一次冒险!) . 欢迎你来看看 .
对于其他任何有几分钟检查的人,我非常感谢您的反馈!
FireFox建议使用它,因为它支持toSource()用于对象查询示例 .
干杯!
亚当
Use inheritance patterns to organize large jQuery applications.
创建假类,并确保任何可以被抛入一个有意义的单独函数的东西都是这样做的 . 还要确保评论很多,而不是编写spagghetti代码,而是将其全部分成几部分 . 例如,一些描述我理想的无意义代码 . 显然在现实生活中我还写了许多基本上包含其功能的库 .
我正在使用这个小东西 . 它为JS和HTML模板提供了'include'指令 . 它完全消除了混乱 .
https://github.com/gaperton/include.js/
遵循良好的OO设计原则和设计模式对于使代码易于维护和理解有很长的路要走 . 但我最近发现的最好的事情之一是信号和插槽,即发布/订阅 . 看看http://markdotmeyer.blogspot.com/2008/09/jquery-publish-subscribe.html是否有一个简单的jQuery实现 .
这个想法很好地用于其他语言的GUI开发 . 当代码中某处发生重要事件时,您将发布一个全局合成事件,其他对象中的其他方法可能会订阅该事件 . 这样可以很好地分离物体 .
我认为Dojo(和Prototype?)有这种技术的内置版本 .
另见What are signals and slots?
以Jquery为中心的NameSpace方式组织代码可能如下所示......并且不会与其他Javascript API(如Prototype,Ext)冲突 .
希望这可以帮助 .
我为我不需要在屏幕上多次实例化的所有东西创建单例,一个用于其他一切的类 . 并且所有这些都放在同一文件中的相同名称空间中 . 所有内容都经过评论,并使用UML状态图进行设计 . javascript代码没有html,所以没有内联javascript,我倾向于使用jquery来最小化跨浏览器问题 .
延迟加载您需要的代码 . Google用他们的google.loader做了类似的事情 .
“写得像疯了一样,只希望它能够做到最好?”,我看到这样一个项目由2位开发人员开发和维护,这是一个包含大量javascript代码的庞大应用程序 . 最重要的是,您可以想到的每个可能的jquery函数都有不同的快捷方式 . 我建议他们将代码组织为插件,因为它是类,类,命名空间和整个Universe的jquery等价物 . 但事情变得更糟,现在他们开始编写插件来替换项目中使用的3行代码的每个组合 . Personaly我认为jQuery是魔鬼,它不应该用于有大量javascript的项目,因为它鼓励你懒惰而不考虑以任何方式组织代码 . 我宁愿阅读100行javascript而不是一行使用40个链式jQuery函数(我不是在开玩笑) . 与流行的看法相反,将javascript代码组织成名称空间和类的等价物非常容易 . 这就是YUI和Dojo所做的 . 如果你愿意,你可以轻松自己动手 . 我觉得YUI的方法更好,更有效率 . 但是,如果你想编写任何有用的东西,你通常需要一个支持片段的好编辑器来补偿YUI命名约定 .
如果javascript内置了命名空间,那将会更好,但我发现像Dustin Diaz这样的组织描述here对我有很大的帮助 .
我将不同的“命名空间”和有时候的单个类放在不同的文件中 . 通常我从一个文件开始,并且作为一个类或命名空间变得足够大以保证它,我把它分成它自己的文件 . 使用工具将所有文件组合起来进行制作也是一个很好的主意 .
Dojo从第一天就开始使用模块系统 . 事实上,它被认为是Dojo的基石,它是将所有这些组合在一起的胶水:
dojo.require — the official doc .
Understanding dojo.declare, dojo.require, and dojo.provide .
Introducing Dojo .
使用模块Dojo实现以下目标:
Dojo代码和自定义代码的命名空间(
dojo.declare()
) - 不污染全局空间,与其他库共存,以及用户的非Dojo感知代码 .按名称同步或异步加载模块(
dojo.require()
) .通过分析模块依赖关系来自定义构建,以创建单个文件或一组相互依赖的文件(所谓的层),以仅包含Web应用程序所需的内容 . 自定义构建可以包括Dojo模块和客户提供的模块好 .
透明的基于CDN的Dojo访问和用户代码 . AOL和谷歌都以这种方式运载Dojo,但是一些客户也为他们的自定义Web应用程序执行此操作 .
受到早期帖子的启发,我制作了 Rakefile 和 vendor 目录的副本,这些目录与WysiHat(由changelog提到的RTE)一起分发,并进行了一些修改,包括使用_268105进行代码检查,并使用YUI Compressor进行缩小 .
我们的想法是使用Sprockets(来自WysiHat)将多个JavaScripts合并到一个文件中,使用JSLint检查合并文件的语法,并在分发之前使用YUI Compressor缩小它 .
Prerequisites
Java运行时
红宝石和耙宝石
您应该知道如何将JAR放入Classpath
Now do
下载Rhino并将JAR("js.jar")放入类路径
下载YUI Compressor并将JAR(build / yuicompressor-xyz.jar)放入类路径
下载WysiHat并将"vendor"目录复制到JavaScript项目的根目录
下载JSLint for Rhino并将其放在"vendor"目录中
现在在JavaScript项目的根目录中创建一个名为“Rakefile”的文件,并将以下内容添加到其中:
如果您已正确完成所有操作,则应该能够在控制台中使用以下命令:
rake merge
- 将不同的JavaScript文件合并为一个rake check
- 检查代码的语法(这是 default 任务,所以你只需键入rake
)rake minify
- 准备JS代码的缩小版本On source merging
使用Sprockets,JavaScript预处理器可以包含(或
require
)其他JavaScript文件 . 使用以下语法来包含初始文件中的其他脚本(名为"main.js",但您可以在Rakefile中更改它):And then...
看看WysiHat提供的Rakefile来设置自动化单元测试 . 好东西 :)
And now for the answer
这不能很好地回答原始问题 . 我知道并且对此感到抱歉,但我在这里发布了它,因为我希望其他人可以组织他们的混乱 .
我解决这个问题的方法是尽可能多地进行面向对象的建模,并将实现分成不同的文件 . 然后处理程序应尽可能短 .
List
单例的例子也不错 .和命名空间......他们可以通过更深层次的对象结构来模仿 .
我不是模仿的忠实粉丝,但如果您有许多想要移出全球范围的物品,这可能会有所帮助 .
您可以使用jquery mx(在javascriptMVC中使用),这是一组允许您使用模型,视图和控制器的脚本 . 我在一个项目中使用它并帮助我创建结构化的javascript,因为压缩而脚本大小最小 . 这是一个控制器示例:
如果您对视图和模型部件不感兴趣,也可以使用jquerymx的only the controller面 .
OO MVC的优秀校长肯定会在管理复杂的JavaScript应用程序方面走得很远 .
基本上我正在组织我的应用程序和javascript到以下熟悉的设计(从我的桌面编程时代到Web 2.0一直存在)
图像上的数值说明:
表示我的应用程序视图的小部件 . 这应该是可扩展的,并且整齐地分离出来,导致MVC试图实现的良好分离,而不是将我的小部件变成意大利面条代码(相当于将大块Javascript直接放在HTML中的Web应用程序) . 每个小部件通过监听其他小部件生成的事件来通过其他小部件进行通信,从而减少小部件之间的强大耦合,这可能导致无法管理的代码(请记住添加onclick的那一天到处指向脚本标记中的全局函数?Urgh ...)
对象模型,表示我想在窗口小部件中填充并来回传递到服务器的数据 . 通过将数据封装到其模型中,应用程序变为数据格式不可知 . 例如:虽然自然在Javascript中这些对象模型大多是序列化和反序列化为JSON,如果服务器以某种方式使用XML进行通信,我需要更改的是更改序列化/反序列化层,而不一定需要更改所有窗口小部件类 .
管理业务逻辑和与服务器的通信的控制器类偶尔会缓存层 . 该层控制与服务器的通信协议,并将必要的数据放入对象模型中
类在它们相应的命名空间中整齐地包装 . 我相信大家都知道Javascript中令人讨厌的全局命名空间 .
在过去,我会将文件分成自己的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)基础设施正是我所需要的 . 我使用它们的原因很少 .
它提供了命名空间支持 . 真正需要OO和整洁的代码组织
它支持类和对象的概念
它提供了一种标准化方法,可以将实例变量添加到您的类中
它整齐地支持类扩展
它提供构造函数和析构函数
它提供渲染和事件绑定
它有基本小部件框架
每个小部件现在都能够使用基于标准事件的模型相互通信
最重要的是,它为所有工程师提供了JO开发的OO标准
与许多观点相反,我不一定要在jQuery和YUI3之间做出选择 . 这两者可以和平共存 . 虽然YUI3为我的复杂Web应用程序提供了必要的OO模板,但jQuery仍然为我的团队提供了易于使用的JS抽象,我们都喜欢和熟悉它们 .
使用YUI3,我已经设法通过分离扩展Base作为Model的类来创建MVC模式,将Widget扩展为View的类,当然你有Controller类进行必要的逻辑和服务器端调用 .
窗口小部件可以使用基于事件的模型相互通信,并根据预定义的界面监听事件并执行必要的任务 . 简单地说,将OO MVC结构放到JS上对我来说是一种快乐 .
只是免责声明,我不为雅虎工作!而且只是一个试图解决原始问题所提出的同一问题的建筑师 . 我想如果有人发现等效的OO框架,这也会有效 . 原则上,这个问题也适用于其他技术 . 感谢所有提出OO Principles MVC的人们,让我们的编程日更易于管理 .