【问题标题】:Javascript OOP best practices? [closed]Javascript OOP 最佳实践? [关闭]
【发布时间】:2011-04-14 14:03:46
【问题描述】:

我厌倦了在 Javascript 中看到数十种不同的面向对象编程方式。考虑到我想从事大型项目并且我希望我的代码能够面向未来,谁能告诉我应该使用哪种技术?

【问题讨论】:

  • Javascript OO syntax 的可能重复项
  • 我喜欢已经有三种不同的 Javascript OO 符号作为这个问题的答案,而问题是提供一个 OP 应该使用的符号。有各种不同的符号 - 我认为,为了清楚起见,每个符号的优缺点应该添加到答案本身,OP 可以做出决定。
  • 如果您需要快速简单的解决方案,请查看github.com/haroldiedema/joii。它允许您使用类、接口和特征/混合,就像您期望的那样工作。它非常小、轻量级,只实现您需要的功能,甚至在 IE6 上也受支持。

标签: javascript oop


【解决方案1】:

这些只是我提出的一些快速指南,如果其他人有任何有意义的补充,我已将此答案设置为社区 wiki,因此您应该可以轻松编辑。

  1. 为您的对象命名空间,以确保它们永远不会与第三方 JavaScript 库发生冲突。
    窗口['安德鲁']['JS'] = {
        addEvent: function(el,evName) {/*Stuff*/},
        矩形: function(width,height) {/*Stuff*/}
    };
    因此,您将使用以下方法创建一个矩形对象:
    var myRect = new Andrew.JS.Rectangle(14,11);
    然后您的代码将永远不会干扰或被其他任何人的Rectangle 干扰。

  2. 使用一致的命名策略,特别是:
    • 对象名称应大写,其他所有内容(变量、函数)应以小写字符开头,即
      var myRect = new Andrew.JS.Rectangle(14,11);
      document.write(myRect.getArea());
    • 确保一切都有意义,即方法的动词,参数的名词 + 形容词。

  3. 确保所有方法和参数都与它们所属的对象相关。例如 在这个例子中,可以使用inSquareFeet()方法将矩形的面积转换为平方英尺。

    myRect.getAreaObject().inSquareFeet();
    确保 inSquareFeet 是 getAreaObject() 返回的对象的方法,而不是 Andrew.JS.Rectangle 的方法

  4. 使用构造函数,或者更具体地说,尽可能努力确保对象在构造后不需要任何进一步的初始化即可使用,所以不要:
    var Person = function()
    {
        这个.name = "";
        this.sayHello = 函数()
        {
            alert(this.name + " 说'你好!'");
            返回这个;
        }
    }
    
    var bob = new Person();
    bob.name = "鲍勃波尔顿";
    bob.sayHello();
    尝试:
    var Person = 函数(名称)
    {
        this.name = 名称;
        this.sayHello = 函数()
        {
            alert(this.name + " 说'你好!'");
            返回这个;
        }
    }
    
    var bob = new Person("Bob Poulton");
    bob.sayHello();

【讨论】:

  • 为什么 window['Andrew']['JS'] = ...window.Andrew.JS = ... 一样好用,打字更少,眼睛更舒服?
  • sayHello 最好被分配给构造函数的原型,像这样 Person.prototype.sayHello = function() {...} 这样该方法对所有 Person 实例都是通用的。您现在这样做的方式效率不高,因为每个 Person 实例都将包含自己的 sayHello 副本。
【解决方案2】:

我总是使用 John resig 的:

http://ejohn.org/blog/simple-javascript-inheritance/

它很简单,不需要任何框架即可运行。

【讨论】:

    【解决方案3】:

    因为您正在处理一个大型项目,我建议您使用像 mootools http://mootools.net/ 这样的 javascript 框架。

    它具有良好的类和继承结构。

    【讨论】:

      【解决方案4】:

      我对 OOP 的理想对象就像使用带有原型的实例方法:

      例子:

      var Users = function()
      {
          var _instance;
          this.prototype.getUsername = function(){/*...*/}
          this.prototype.getFirstname = function(){/*...*/}
          this.prototype.getSecurityHash = function(){/*...*/}
          /*...*/
      
          /*Static Methods as such*/
          return { /*Return a small Object*/
              GetInstance : function()
              {
                  if(_instance == null)
                  {
                      _instnance = new Users(arguments);
                  }
                  return _instnance; //Return the object
              },
              New: function()
              {
                  _instnance = null; //unset It
                  return this.GetInstnace(arguments);
              }
          }
      }
      

      那我总是用like:

      Firstname = Users.GetInstance('Robert','Pitt').getFirstname();
      Username  = Users.GetInstance().getUsername(); //Returns the above object.
      
      Me  = Users.New('Robert',null); //Deletes the above object and creates a new instance.
      Father = Users.New('Peter','Piper'); //New Object
      Me.AddFather(Father); //Me Object.
      

      这就是我在构建 JavaScript OO 风格架构时所走的道路。

      【讨论】:

      • 如前所述,Users 没有GetInstance 属性。您的意思是在将结果分配给用户之前调用匿名函数吗?
      【解决方案5】:

      仅供参考,我认为YUI 提供了一些关于此主题的精彩教程

      【讨论】:

        【解决方案6】:
        //Create and define Global NameSpace Object
        ( function(GlobalObject, $, undefined) 
        {
            GlobalObject.Method = function()
            {
                ///<summary></summary>
            }
        
            GlobalObject.Functionality = {};
        
        }) (GlobalObject = GlobalObject || {}, jQuery);
        
        //New object for specific functionality
        ( function(Events, $, undefined)
        {
            //Member Variables 
            var Variable; // (Used for) , (type)
        
            // Initialize
            Events.Init = function()
            {
                ///<summary></summary>
            }
        
            // public method
            Events.PublicMethod = function(oParam)
            {
                ///<summary></summary>
                ///<param type=""></param>
            }
        
            // protected method (typically define in global object, but can be made available from here)
            GlobalObject.Functionality.ProtectedMethod = function()
            {
                ///<summary></summary>
            }
        
            // internal method (typically define in global object, but can be made available from here)
            GlobalObject.InternalMethod = function()
            {
                ///<summary></summary>
            }
        
            // private method
            var privateMethod = function()
            {
                ///<summary></summary>
            }
        }) (GlobalObject.Funcitonality.Events = GlobalObject.Funcitonality.Events || {}, jQuery )
        
        // Reusable "class" object
        var oMultiInstanceClass = function()
        {
            // Memeber Variables again
            var oMember = null; // 
        
            // Public method
            this.Init = function(oParam)
            {
                oMember = oParam;
        
                for ( n = 1; i < oMemeber.length; i += 1 )
                { 
                   new this.SubClass.Init(oMember[i]); // you get the point, yeah?
                }
            }
        
            this.Subclass = function()
            {
                this.Init = function() { }
            }
        }
        

        这样做的优势在于它会自动初始化 Global 对象,允许您保持代码的完整性,并根据您的定义将每个功能组织到一个特定的组中。

        这个结构很稳固,呈现了您对 OOP 的所有基本句法知识,而没有关键字。

        甚至还有一些巧妙的方法来设置界面。如果你选择走那么远,a simple search 会给你一些很好的教程和技巧。

        即使 setting up intellisense is possible 使用 javascript 和 Visual Studio,然后定义每个部分并引用它们,也可以使编写 javascript 更清晰、更易于管理。

        根据您的情况使用这三种方法有助于保持全局命名空间清洁、保持代码井井有条并保持每个对象的关注点分离。如果使用正确。请记住,如果您不利用使用对象背后的逻辑,那么面向对象的设计将毫无用处!

        【讨论】:

          【解决方案7】:
          function foo() {
            var bar = function() { console.log("i'm a private method"); return 1; };
            var iAmAPrivateVariable = 1;
          
            return {
              publicMethod: function() { alert(iAmAPrivateVariable); },
              publicVariable: bar()
            }
          }
          
          //usage
          var thing = foo()
          

          这是一种功能性方法,与您将看到的其他任何东西相比,它有更多的用途(例如封装)

          一般来说,你不应该在 javascript 中做 OO,因为很多原因,它并不是一种很好的语言。考虑带有波浪括号和分号的方案,您将开始像专业人士一样编写语言。话虽如此,有时OO更适合。在这些情况下,上述方法通常是最好的选择

          将继承引入混合

          function parent() {
            return { parentVariable: 2 };
          }
          
          function foo() {
            var bar = function() { console.log("i'm a private method"); return 1; };
            var iAmAPrivateVariable = 1;
          
            me = parent();
            me.publicMethod = function() { alert(iAmAPrivateVariable); };
            me.publicVariable = bar();
          
            return me;
          }
          

          这使事情变得更加复杂,但在实现期望的最终结果的同时仍然采用面向 OO 概念的函数式方法(在这种情况下,使用装饰器函数而不是真正的继承)。我喜欢整个方法的一点是,我们仍然以这种语言的预期方式处理对象——一个你可以随意附加东西的属性包。

          另一个注意事项是,这与您在大多数工作中看到的情况大不相同,而且通常很难解释 a) 发生了什么,b) 为什么会这样对同事来说是个好主意。

          【讨论】:

            【解决方案8】:

            我使用这样的模式并推荐给你也使用它:

            function Person(firstname, lastname, age)
            {
              var self = this;
              var _ = {};
            
              // Private members.  
              var firstname  = firstname;
              var lastname = lastname;
              var age = age || 'unknown';
            
              // Private methods.
              function first_letter_to_uppercase(str) {
                return str.charAt(0).toUpperCase() + str.substr(1);
              }
            
              // Public members and methods.
              _.get_age = function()
              {
                return age;
              }
            
              _.get_name = function()
              {
                return first_letter_to_uppercase(firstname) + ' ' +
                  first_letter_to_uppercase(lastname);
              }
              return _;
            }
            
            var p = new Person('vasya', 'pupkin', 23);
            alert("It's "  + p.get_name() + ', he is ' + p.get_age() + ' years old.') 
            

            【讨论】:

            • 通过从函数 Person 返回一个对象,您将失去继承。您不能再通过向Person.prototype 添加属性来扩展实例的行为。
            • var firstname = firstname 位是不必要的,因为参数firstname 已经是一个私有变量。
            【解决方案9】:

            您可以尝试使用简单、有用且快速的对象:

            var foo = {
                foo1: null,
                foo2: true,
                foo3: 24,
                foo4: new Array(),
            
                nameOfFunction1: function(){
                  alert("foo1");
                },
            
                nameOfFunction2: function(){
                  alert("foo2");
                },
            }
            

            要使用它,你必须创建这个对象的一个​​实例并像java中的对象一样使用:

            foo.nameOfFunction2();
            

            您也可以查看此链接到其他解决方案:http://www.javascriptkit.com/javatutors/oopjs.shtml

            我希望能回答你的问题。

            【讨论】:

            • 由于foo 不是函数,new foo() 将失败。
            • 是的。你说得对。对不起。我已经重写了调用。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-06-19
            • 2010-09-22
            • 2014-01-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多