问题 JavaScript中的Java-esque OOP和jQuery失败


我正在研究一个项目,我真的想编写面向对象的JavaScript代码。我刚开始读书 道格拉斯克罗克福德的JavaScript:好的部分 我很快就意识到在JavaScript中编写Java-esque OOP将是一项艰巨的任务。

到目前为止,我写了类似下面的内容......

// 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中改进我的OOP方法的建议,我希望看到有关讨论此主题的资源/教程/文章/等的参考资料。即使选择了答案,也请随时提供反馈。我正在寻找你的建议......这就是我发布的原因:)

**注意:我没有开发jQuery插件。我正在开发一个Web应用程序并大量使用jQuery。


7207
2018-03-29 19:46


起源

看一下require.js来处理大中型项目的文件加载和依赖项。 - Raynos
@Raynos ......绝对会看一看。是那样的 headjs.com - Hristo


答案:


我想说你创建方法的第一种方式是滥用jQuery。该 jQuery.fn.foo 语法通常保留给作用于DOM元素但通过使用空jQuery对象将它们用作静态函数的函数。

如果要在jQuery命名空间下创建静态函数,可以执行以下操作:

jQuery.foo = function(){};

然后通过以下方式调用

jQuery.foo();

代替:

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

这可以让你做到:

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

就OOP而言。有许多不同的方法(模块模式,原型,工厂......)。我通常接近它的方法是创建一个Class作为静态函数,然后使用关键字调用它 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);

在重用功能方面,有一个阈值,之后解耦比任何事情都更有害。确保您保持模块化和组织的正确平衡。


3
2018-03-29 20:03



@alex ...这看起来不错,谢谢!您所写的内容与其他用户建议的“命名空间”理念有何不同? - Hristo
@Hristo嗯,我实际上只是将它放入jQuery命名空间。这里的大多数人都在反对它,所以我的代码可以很容易地改为YOURNAMESPACE.ClassName = function(){} - Alex Heyd
@alex ...哦,我明白了。 - Hristo
另外,@ Hristo,我在这里使用的模式还有争议。有很多选择,选择最适合您的情况。我并不总是使用上述格式,大部分时间都是如此。例如,如果我计划拥有许多类的实例,我会出于性能/内存的原因将这些方法分解为类原型。 - Alex Heyd
@alex ...感谢您的解释。一旦我获得我的upvoting权限+1就+1 - Hristo


如果它不是一个jquery插件,我会写这样的东西:

    var app = {
      init: function(){
        app.SetUpElements();
      },
      SetUpElements: function() {
        return 'something';
      }, 
      etc: function() {

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

6
2018-03-29 20:01



@minibikini ...变量是什么 app 代表? - Hristo
这就是@jamietre通过“设置自己的命名空间”的含义。 app 是您的命名空间全局对象,它将包含您的分组函数和属性。 app 应该是一个非常独特的应用程序名称,因为它是您的主要全局对象。 - mVChr
@mVChr ...太棒了,谢谢! - Hristo
现在将它包裹在一个封闭中!所以你不要污染全球范围 app - Raynos


关于在Javascript中执行OO,您应该注意 Douglas Crockford的高级Javascript课程


4
2018-03-29 19:55



@mlaw ......我实际上开始阅读他的书“JavaScript - The Good Parts”。我肯定会查看课程。谢谢! - Hristo
这些视频比这本书更具信息量。虽然我将强制引用另一本书--JavaScript:The Definitive Guide(amazon.com/JavaScript-Definitive-Guide-David-Flanagan/dp/...)。


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

看一下 这个关于jQuery网站的文档,它提供了一个很好的解释,说明如何提供对各种可重用功能的访问,同时只在jQuery对象上声明一个名称。

我看到的另一种方法是在jQuery命名空间上为你的插件提供单个init函数,然后在Global命名空间中提供一个额外的插件特定名称,它提供对函数/成员的更直接访问等。该 Galleria插件 是如何做到这一点的一个很好的例子。检查他们的文档,以及他们设置插件结构的方式。

编辑

看到你之后  制作一个插件:我所说的许多内容仍然适用于一般的jQuery开发(实际上,一般来说也适用于开发)。

在您的特定情况下,由于您没有在进行函数调用时使用jQuery选择器,因此这些函数可能很容易附加到您自己制作的原型上,可以放在Global命名空间中。

就名称空间而言,请查看此问题的已接受答案,以获取如何正确执行此操作的示例: 如何在JavaScript中声明命名空间?

这里是JavaScript中OO的一个很好的资源。我试图围绕这个概念时使用这篇文章: http://mckoss.com/jscript/object.htm


1
2018-03-29 19:51



@Ender ...... 1.我爱你的名字:) 2.我是 不 开发插件。 - Hristo
@Ender ...感谢“编辑”。这是我想要进入的方向。现在,我已经看过两次对“命名空间”的引用......这是什么?如何/在哪里可以了解有关创建自己的命名空间的更多信息 - Hristo
我刚刚添加了对另一个SO问题的引用 希望 会回答那个问题:) - Ender
@Ender ...太棒了,谢谢!一旦我能够恢复我的提升能力,我会给你一个+1。 - Hristo
@Hristo - 谢谢,很高兴我可以帮忙:)如果你需要进一步阅读,请尝试一些关于javascript原型的谷歌搜索。有很多资源解释如何做(以及为什么)。 - Ender


您好像将所有代码都编写为jQuery插件?我不会这样做。创建自己的命名空间。

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

面向对象编程并不意味着跨文件分段。这只是组织,当你不需要某些页面上的所有内容时,你应该把东西分成不同的文件。


0
2018-03-29 19:55



@jamietre ......嗯...这很有道理!我不是想写一个插件,所以我看到我的错误在哪里。我跨文件传播的原因是我可以将特定功能组合在一起并轻松找到它,这样我就不必滚动浏览一个巨大的文件。 “创建自己的命名空间”是什么意思?你能提供解释/来源/链接等等吗? - Hristo


正如大多数人已经提到的,除非您明确创建公共插件,否则不要使用jQuery自定义函数。而是使用简单的对象表示法创建自己的命名空间,或者像 模块模式。如果你想变得疯狂,可以在API之上使用API​​,通过使用获得更经典的OO模式 迪安爱德华基地。最终目标是从jQuery API中提取您的功能和设计需求。这样,如果您需要将某些东西移植到Mootools或Prototype,那么完成起来会更简单。


0
2018-03-29 20:01



@ hal10001 ...你能提供更多关于创建命名空间的信息吗?这实际上是我第一次听说这个词:/ - Hristo