Это хороший способ сделать JS OOP? - PullRequest
8 голосов
/ 12 августа 2009

Я хотел спросить о плюсах и минусах моего следующего стиля ООП. Я пишу свои классы 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");

Это хороший подход? Есть ли недостаток? Я не использую наследование, но будет ли он работать таким образом, чтобы добиться наследования?

Заранее спасибо.

Ответы [ 6 ]

6 голосов
/ 12 августа 2009

Я думаю, что это очень хороший подход. Не стыдитесь вопроса «без наследства». Большинство ООП не о наследовании. Наиболее важные аспекты - это инкапсуляция и полиморфизм, и вы их получили.

Можно утверждать (ну, я обычно утверждаю), что наследование необходимо только для статических языков, где вы должны как-то сказать компилятору, что эти два типа (классы) связаны, что у них есть что-то общее (общее предок), так что это может позволить полиморфизм. С динамическими языками OTOH компилятору все равно, а среда выполнения найдет общие черты без какого-либо наследования.

Еще один момент: если вам нужно какое-то наследование в некоторых местах (а оно отлично в некоторых случаях, например, в графических интерфейсах), часто вы обнаружите, что вы можете легко взаимодействовать между вашим «простым» объекты / классы и другие, более сложные и тяжелые. IOW: не пытайтесь найти структуру, которая отвечает всем вашим потребностям, и использовать ее для всего; вместо этого используйте тот, который вам удобнее в каждый момент, если он помогает с конкретной проблемой.

3 голосов
/ 12 августа 2009
2 голосов
/ 12 августа 2009

На самом деле, это не отличается от способа, которым это обычно делает 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
    }
  };
})();

Преимущество вышеописанного заключается в том, что вы сможете быстро и легко управлять наследованием. В вашем случае наследование (или, по крайней мере, переопределение функций) практически невозможно без создания какой-либо формы внешней вспомогательной функции, как описано выше.

1 голос
/ 12 августа 2009

Я всегда считал, что веб-сайт Дугласа Крокфорда является бесценным ресурсом для лучших практик JavaScript. Так уж сложилось, что он написал несколько статей, имеющих отношение к вашему вопросу.

0 голосов
/ 14 сентября 2011

Вы также можете просто использовать литералы и компоновщики. Таким образом, вам не придется использовать менее привлекательные концепции в 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

0 голосов
/ 12 августа 2009

Если вы ищете более наследуемую структуру классов в JavaScript, вы можете проверить Dojo .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...