【问题标题】:Is this a good way to do JS OOP?这是做 JS OOP 的好方法吗?
【发布时间】:2009-08-11 21:42:20
【问题描述】:

我想问一下我下面的 OOP 风格的优缺点。 我以以下方式编写我的 JS 类。

var MyClass = function() {
    // private vars
    var self = this,
        _foo = 1,
        _bar = "test";

    // public vars
    this.cool = true;

    // private methods
    var initialize = function(a, b) {
        // initialize everything
    };

    var doSomething = function() {
        var test = 34;
        _foo = cool;
    };

    // public methods
    this.startRequest = function() {

    };

    // call the constructor
    initialize.apply(this, arguments);
};

var instance_1 = new MyClass();
var instance_2 = new MyClass("just", "testing");

这是一个好方法吗?有什么缺点吗? 我不使用继承,但是这样可以实现继承吗?

提前致谢。

【问题讨论】:

    标签: javascript oop


    【解决方案1】:

    我认为这是一个非常好的方法。不要为“不继承”的问题感到羞耻。大多数 OOP 与继承无关。最重要的方面是封装和多态性,您已经掌握了它们。

    可以说(好吧,我通常认为)继承只需要静态语言,你必须以某种方式告诉编译器这两种类型(类)是相关的,它们有一些共同点(共同点)祖先),以便它可以允许多态性。使用动态语言,OTOH,编译器不会关心,运行时环境会在没有任何继承的情况下找到共性。

    另外一点:如果您在某些地方需要一些继承(在某些情况下它很棒,例如 GUI),您通常会发现您可以轻松地在您的“简单' 对象/类,以及其他更复杂和更重的。 IOW:不要试图找到一个可以满足你所有需求的框架并将其用于所有事情;只要它有助于解决特定问题,请改为使用您在每一刻都更熟悉的那个。

    【讨论】:

    • +1 for - 最重要的方面是封装和多态性。
    • 这里也是+1。在许多关于 OO 的文章中,继承当然被过度重视。在过去的几年里,我才刚刚开始有效地使用 OO 进行编程,而且我已经忘记了由于过度依赖继承而导致的新手错误。
    【解决方案2】:

    【讨论】:

    • 请注意,Douglas 在“获得”原型继承后就弃用了“JavaScript 中的经典继承”一文
    【解决方案3】:

    实际上,这与 Prototype.js(我最喜欢的库)通常的做法没有什么不同。如果你看这里:

    var Class = (function() {
      function subclass() {};
    
      // All classes are created through Class.create( {/*JSON Object*/} );
      // or Class.create( function, ...properties );
      // The first form will create a unique class.
      // The second form will create a Class which subclasses the initial function.
      function create() {
    
        var parent = null, 
                         // $A just normalizes the array.
            properties = $A(arguments);
    
        // Which type of class definition was used?
        if (Object.isFunction(properties[0]))
          parent = properties.shift();
    
        // This effectively creates a constructor
        function klass() {
          this.initialize.apply(this, arguments);
        }
    
        // Allows klass to have addMethods property
        Object.extend(klass, Class.Methods);
        klass.superclass = parent;
        klass.subclasses = [];
    
        // Does this class have a parent class?
        if (parent) {
          subclass.prototype = parent.prototype;
          klass.prototype = new subclass;
          parent.subclasses.push(klass);
        }
    
        // Add methods to the class
        for (var i = 0; i < properties.length; i++)
          klass.addMethods(properties[i]);
    
        // emptyFunction = function(){};
        if (!klass.prototype.initialize)
          klass.prototype.initialize = Prototype.emptyFunction;
    
        // Creates the constructor
        klass.prototype.constructor = klass;
        return klass;
      }
    
      function addMethods(source) {
        // Does this class have a parent?
        var ancestor   = this.superclass && this.superclass.prototype;
    
        // Grab the keys of a JSON object
        var properties = Object.keys(source);
    
        // Makes sure each object has a toString and valueOf method.
        if (!Object.keys({ toString: true }).length) {
          if (source.toString != Object.prototype.toString)
            properties.push("toString");
          if (source.valueOf != Object.prototype.valueOf)
            properties.push("valueOf");
        }
    
        //Loop through the properties.
        for (var i = 0, length = properties.length; i < length; i++) {
    
          // property is the Key in the JSON, value is the corresponding
          // method or property value.
          var property = properties[i], value = source[property];
          if (ancestor && Object.isFunction(value) &&
              value.argumentNames().first() == "$super") {
    
            // Handles an override of a parent method.
            var method = value;
            value = (function(m) {
              return function() { return ancestor[m].apply(this, arguments); };
            })(property).wrap(method);
    
            value.valueOf = method.valueOf.bind(method);
            value.toString = method.toString.bind(method);
          }
          this.prototype[property] = value;
        }
    
        return this;
      }
    
      // And here is the final value!
      return {
        create: create,
        Methods: {
          addMethods: addMethods
        }
      };
    })();
    

    上述的好处是您将能够快速轻松地管理继承。在你的情况下,如果不创建某种形式的外部辅助函数,几乎不可能继承(或者至少是覆盖函数)。

    【讨论】:

      【解决方案4】:

      我一直认为 Douglas Crockford 的网站是 JavaScript 最佳实践的宝贵资源。碰巧他写了几篇与您的问题相关的文章。

      【讨论】:

        【解决方案5】:

        如果您正在 JavaScript 中寻找更多基于类的继承结构,您可能需要查看Dojo

        【讨论】:

          【解决方案6】:

          您也可以只使用文字和构建器。这样您就不必使用 Javascript 中不太吸引人的概念:原型、新语句和 this 关键字。

          基本配方很简单:

          • 创建一个构建文字对象的函数
          • 将该函数放入文字对象中

          具有构建器的文字充当类。构建器函数充当构造函数,生成的文字充当类实例。

          这是一个例子:

          Car = {
              createNew:function() { //no prototype!
                  var obj = {};
                  var color;
                  obj.setColor = function(c) { color = c; }
                  obj.drive = function(){ alert('driving a '+color+' car'); }
                  return obj; //no this-keyword!
              }
          }
          
          var car = Car.createNew(); //no new statement!
          car.setColor('red');
          car.drive();
          

          更多文档可以在这里找到:

          http://www.gabordemooij.com/jsoop.html

          这里

          https://github.com/schuttelaar/Rococo2/wiki/Getting-started

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-03-02
            • 1970-01-01
            • 2011-07-07
            • 1970-01-01
            • 2011-05-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多