tags:

views:

180

answers:

5

I wanted to ask about the pros cons of my the following OOP style. I write my JS classes in the following manner.

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");

Is this a good approach? Is there any drawback? I don't use inheritance, but would it work this way to achieve inheritance?

Thanks in advance.

+2  A: 

I found those articles by Douglas Crockford very informative:

weichsel
note that the Douglas deprecated the "Classical Inheritance in JavaScript" article once he 'got' the prototypal inheritance
Javier
A: 

I've always found Douglas Crockford's Web site to be an invaluable resource for JavaScript best-practices. It just so happens that he's written several articles pertinent to your question.

Christopher Parker
A: 

Actually, that not dissimilar from the way that Prototype.js (my favorite library) generally does it. If you look here:

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
    }
  };
})();

The benefit of above is that you'll be able to manage inheritance quickly and easily. In your case inheritance (or, at least, overriding functions) is almost impossible without creating some form of external helper function like above.

Christopher W. Allen-Poole
+2  A: 

I think it's a very good approach. Don't be ashamed of the 'no inheritance' issue. Most OOP isn't about inheritance. The most important aspects are the encapsulation and polymorphism, and you've got them.

It can be argued (well, i usually argue) that inheritance is only needed for static languages, where you have to somehow tell the compiler that these two types (classes) are related, that they have something in common (the common ancestor) so that it can allow polymorphism. With dynamic languages, OTOH, the compiler won't care, and the runtime environment will find the commonalities without any inheritance.

Another point: if you need some inheritance in some places (and it's great in some cases, like GUIs, for example), often you'll find that you can easily interoperate between your 'simple' objects/classes, and other more complex and heavier. IOW: don't try to find a framework that fills all your needs and use it for everything; instead use the one that you're more comfortable with at each moment, as long as it helps with the specific problem.

Javier
+1 for - The most important aspects are encapsulation and polymorphism.
Everyone
A: 

If you're looking for a more class based inheritance structure within JavaScript you might want to check out Dojo.