JavaScript中的类似Java的面向对象编程和一个jQuery失败

11
我正在进行一个项目,尝试编写面向对象的JavaScript代码。我刚开始阅读Douglas Crockford的《JavaScript高级程序设计》,很快就意识到在JavaScript中编写类似Java的面向对象编程将是一项艰巨的任务。
到目前为止,我已经写了以下类似的代码...
// index.html
$(document).ready(function() {

   $().SetUpElements();
});

// this is in a different js file
$.fn.SetUpElements = function() {

    // do stuff here
    $().UpdateElement();
};

// this is in yet another different js file
$.fn.UpdateElement = function() {

   // do stuff here
   var element = new Element(id, name); // continue doing work
};

function Element(id, name) {

   var id = id;
   var name = name;

   // other stuff
};

我希望尽可能地重构和解耦对象/函数,以便能够最大程度地重用代码。我已经将很多代码分散在不同的.js文件中,目的是将特定相关代码分组在一起,就像在Java中编写不同的类一样。
随着我对jQuery的学习越来越深入,我意识到符号$.fn.foo = function() { ... };实际上是将这个foo函数添加到所有jQuery对象的原型中。这是我应该做的吗?我是否在错误地使用jQuery?
我希望得到关于如何改进JavaScript中面向对象编程方法的建议,并且我想看到讨论这个主题的参考资料/教程/文章等。即使已经选择了答案,请随时提供反馈。我正在寻求您的建议...这就是为什么我发布了这篇文章 :)
**注意:我没有开发jQuery插件。我正在开发一个Web应用程序,并且大量使用jQuery。

看一下 require.js,它可以处理中大型项目的文件加载和依赖。 - Raynos
@Raynos...一定会看一下。那个和http://headjs.com/类似吗? - Hristo
6个回答

6
如果不是一个jQuery插件,我会写出以下代码:
    var app = {
      init: function(){
        app.SetUpElements();
      },
      SetUpElements: function() {
        return 'something';
      }, 
      etc: function() {

      }
    };
   $(document).ready(app.init);

@minibikini... 变量 app 代表什么? - Hristo
这就是@jamietre所说的“设置自己的命名空间”的意思。app是你的命名空间全局对象,它将包含你分组的函数和属性。app应该是非常独特的应用程序名称,因为它是你的主要全局对象。 - mVChr
1
现在将其包装在闭包中!这样您就不会使用 app 污染全局范围。 - Raynos

4

@mlaw... 我正在阅读他的书《JavaScript - The Good Parts》。我一定会去看这些课程的。谢谢! - Hristo
这些视频比书本更加丰富和信息量大。尽管我会提及另外一本书 - 《JavaScript 权威指南》(http://www.amazon.com/JavaScript-Definitive-Guide-David-Flanagan/dp/0596101996/ref=sr_1_2?ie=UTF8&qid=1301429052&sr=8-2)。 - user4903

3

我认为第一种方式创建方法是滥用jQuery。 jQuery.fn.foo 语法通常保留用于作用于DOM元素的函数,但您正在使用它们作为静态函数,通过使用空的jQuery对象。

如果你想在jQuery命名空间下创建静态函数,可以这样做:

jQuery.foo = function(){};

然后通过以下方式调用:

jQuery.foo();

替代方案:

jQuery.fn.foo = function(){};

这使得你可以做以下事情:

jQuery('#someElementId').foo();

从面向对象编程的角度来看,有许多不同的方法(模块模式、原型、工厂...)。我通常的做法是创建一个类作为静态函数,然后使用关键字new调用它。

(function($){
    var undefined;

    $.ClassName = function(options){
        var self = this;
        var cfg = $.extend(true, {}, this.defaults, options);

        // ********************
        // start:private
        // ********************
        function _init(){

        };

        // ********************
        // start:public
        // ********************
        this.methodName = function(){

        };

        _init();
    };

    $.ClassName.prototype.defaults = {};
})(jQuery);

在重用功能方面,有一个阈值,超过这个阈值后,解耦会变得更加不利。确保您保持适当的模块化和组织。


@alex... 这看起来不错,谢谢!你写的和其他用户建议的“命名空间”有什么不同? - Hristo
@Hristo 嗯,实际上我只是把它放到了jQuery命名空间中。这里大多数人都建议不要这样做,所以我的代码很容易被改成YOURNAMESPACE.ClassName = function(){}。 - Alex Heyd
此外,@Hristo,我在这里使用的模式是有争议的。有许多替代方案,选择最适合您情况的方案。我并不总是使用上述格式,只是大多数情况下使用。例如,如果我计划拥有许多类的实例,则出于性能/内存原因,我会将方法拆分到类原型中。 - Alex Heyd
@alex... 我很感激你的解释。一旦我恢复了我的投票特权,我会给你点赞的 :) - Hristo
@alex... 在你在场的时候... 你对这行代码 var cfg = $.extend(true, {}, this.defaults, options); 做了什么? - Hristo
@Hristo 这个函数会将默认选项和传入的选项合并,这样你就可以定义一组默认选项,用参数覆盖它们,如果某个属性没有被指定,它就使用默认值。http://api.jquery.com/jQuery.extend/ - Alex Heyd

1

如果您正在开发插件,通常最好尽可能避免污染jQuery和全局命名空间/原型。

请查看jQuery网站上的此文档,其中详细解释了如何提供对各种可重用功能的访问,同时仅在jQuery对象上声明一个名称。

我见过的另一种方法是在jQuery命名空间上提供单个初始化函数,然后在全局命名空间中提供一个额外的插件特定名称,以提供更直接的访问功能/成员等。 Galleria插件是如何很好地实现这一点的绝佳示例。请查看他们的文档以及他们设置插件结构的方式。

编辑

在看到您不是在制作插件之后:我说的许多事情仍适用于一般的jQuery开发(实际上也适用于一般开发)。

在您的特定情况下,由于您在函数调用中没有使用jQuery选择器,这些函数可能很容易地附加到您自己制作的原型上,该原型可以放置在全局命名空间中。
至于命名空间,可以查看此问题的已接受答案,以了解如何正确执行:如何在JavaScript中声明命名空间? 这是一个关于JavaScript面向对象编程的绝佳资源。当我试图理解这个概念时,我使用了这篇文章:http://mckoss.com/jscript/object.htm

@Ender... 1. 我喜欢你的名字 :) 2. 我不是在开发插件。 - Hristo
@Ender...谢谢你的"编辑"。这就是我想要的方向。现在,我已经两次看到了关于"命名空间"的引用...那是什么?我可以在哪里学习更多有关创建自己命名空间的知识? - Hristo
我刚刚添加了对另一个SO问题的引用,希望能够回答那个问题 :) - Ender
@Ender...太棒了,谢谢!一旦我能恢复我的点赞能力,我会给你一个+1。 - Hristo
@Hristo - 谢谢,很高兴能帮到你 :) 如果你需要更多阅读材料,可以尝试一些关于JavaScript原型的谷歌搜索。有大量的资源解释如何做(以及为什么)。 - Ender
@Ender... 我一定会在不久的将来进行谷歌搜索。我在这里的目标是快速获取SO社区已经知道的最好资源的参考资料 :) - Hristo

0

看起来你把所有的代码都写成了jQuery插件?我不会这样做。创建自己的命名空间。

把所有东西放在不同的文件中有什么目的?除非它们是将用于特定页面的脚本,否则这只会使事情更难管理。这些都看起来像是通用库函数。除非你认为你想要在一个页面上加载一些而不是全部,否则把它们都放在一个文件中。

面向对象编程并不意味着将东西分散在不同的文件中。那只是组织,当你不需要某个页面上的所有内容时,应该将它们拆分成不同的文件。


@jamietre... 嗯...这很有道理!我不是在尝试编写插件,所以我知道我的错误在哪里。我将事物分散到文件中的原因是为了将特定功能分组并轻松定位它们,以便我不必滚动一个巨大的文件。你说的“创建自己的命名空间”是什么意思?你能提供一些解释/来源/链接等吗? - Hristo

0

正如大多数人已经提到的那样,除非您明确地创建了一个公共插件,否则不要使用jQuery自定义函数。相反,使用直接对象符号或更强大的模块模式来创建自己的命名空间。如果您想变得疯狂一点,可以在Dean Edward's Base上使用API来获取更经典的OO模式。最终目标是从jQuery API中提取您的功能和设计要求。这样,如果您需要将某些内容移植到Mootools或Prototype上,就会更加简单。


@hal10001... 你能提供更多有关创建命名空间的信息吗?这是我第一次听到这个术语 :/ - Hristo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接