随着像jQuery这样的JavaScript框架使客户端web应用程序更丰富,功能更强大,我开始注意到一个问题…

你到底是怎么组织起来的?

把所有的处理程序放在一个地方,并为所有事件编写函数? 创建函数/类来包装您的所有功能? 疯狂地写作,只希望结果是最好的? 放弃,找一份新工作?

我提到了jQuery,但它实际上是一般的JavaScript代码。我发现,当一行一行开始堆积时,管理脚本文件或找到您要找的内容变得越来越困难。我发现的最大问题可能是,做同一件事有太多的方法,很难知道哪一种是目前普遍接受的最佳实践。

有什么通用的建议可以让你的.js文件像你的应用程序的其他部分一样漂亮整洁吗?或者这只是IDE的问题?还有更好的选择吗?


EDIT

这个问题主要是关于代码组织,而不是文件组织。有一些合并文件或拆分内容的好例子。

我的问题是:目前普遍接受的组织实际代码的最佳实践方式是什么?您的方法是什么,甚至推荐的方法是什么,以与页面元素交互并创建互不冲突的可重用代码?

有些人列出了名称空间,这是个好主意。还有什么其他方法,更具体地说,处理页面上的元素并保持代码的组织和整洁?


当前回答

您可以将脚本分解为单独的文件进行开发,然后创建一个“发布”版本,在这个版本中,您可以将它们全部塞在一起,并在上面运行YUI Compressor或类似的程序。

其他回答

受之前帖子的启发,我制作了一个Rakefile和供应商目录的副本,并与WysiHat (changelog提到的RTE)一起分发,并进行了一些修改,包括使用JSLint进行代码检查和使用YUI Compressor进行缩小。

这个想法是使用Sprockets(来自WysiHat)将多个JavaScripts合并到一个文件中,在发布之前用JSLint检查合并文件的语法,并用YUI Compressor缩小它。

先决条件

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

现在做的

下载Rhino并将JAR(“js.jar”)放到类路径中 下载YUI Compressor并将JAR (build/yuicompressor-xyz.jar)放到类路径中 下载WysiHat并将“vendor”目录复制到你的JavaScript项目的根目录 下载JSLint for Rhino,并将其放到“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检查——检查代码的语法(这是默认任务,因此只需输入Rake) rake minify——准备JS代码的缩小版本

关于源合并

使用Sprockets, 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 singleton的例子也是一个很好的例子。

和名称空间……它们可以被更深层次的物体结构所模仿。

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

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

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

我不太喜欢模仿,但是如果您有很多想要移出全局作用域的对象,这可能会很有帮助。

对于JavaScript组织一直使用以下

Folder for all your javascript Page level javascript gets its' own file with the same name of the page. ProductDetail.aspx would be ProductDetail.js Inside the javascript folder for library files I have a lib folder Put related library functions in a lib folder that you want to use throughout your application. Ajax is the only javascript that I move outside of the javascript folder and gets it's own folder. Then I add two sub folders client and server Client folder gets all the .js files while server folder gets all the server side files.

我的老板仍然在谈论他们编写模块化代码(C语言)的时代,并抱怨现在的代码是多么糟糕!据说程序员可以在任何框架中编写程序集。总有一种策略可以克服代码组织。最基本的问题是那些把java脚本当作玩具的人,从来没有尝试去学习它。

在我的例子中,我在UI主题或应用程序屏幕的基础上编写js文件,使用适当的init_screen()。使用适当的id命名约定,我确保在根元素级别上没有名称空间冲突。在不引人注目的window.load()中,我根据顶级id将内容绑定起来。

我严格使用java脚本闭包和模式来隐藏所有私有方法。这样做之后,再也没有遇到属性/函数定义/变量定义冲突的问题。然而,当与团队一起工作时,通常很难执行同样的严格性。

我尽量避免在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类将是一个标准的javascript类,只是恰好使用jQuery。

// 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>');
  //...
};

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

以Jquery为中心的命名空间方式组织您的代码可能看起来如下…并且不会与其他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>

希望这能有所帮助。