21
votes

How can I emulate classes (and namespaces) in JavaScript?

I need to create a JavaScript library and have limited experience with the language. I always thought that it had native support for classes, but it is less related to Java than I had assumed. It seems that everything in JavaScript is actually a function.

What I have found out so far makes a lot of sense with it being a dynamic weakly typed language, but this makes it a bit of a departure for people who are used to having a strongly typed language and using a compiler to spot our errors :)

I mainly work in C# and Java, and was hoping for something syntacticaly similar so the library would look familiar for our other C# developers that will have to maintain it.

I have the following sort of code which works, but I was wondering what other developer's takes would be on this. What are the alternatives? Is there a way that is better? Is there a way that is more readable?

I understand that what I want is something similar to C# or Java when I should just accept the fact that this is JavaScript, but my aim is to try to ease the learning curve for other developers by making it more familiar and intuitive for them.

//Perform the namespace setup (this will actually be done with checking 
//in real life so we don't overwrite definitions, but this is kept short 
//for the code sample).
var DoctaJonez = new function();
DoctaJonez.Namespace1 = new function();

/**
 * Class description.
 */
DoctaJonez.Namespace1.SomeClass = function()
{
    /**
     * Public functions listed at the top to act like a "header".
     */
    this.publicFunction = privateFunction;

    /**
     * Private variables next.
     */
    var privateVariable;

    /**
     * Finally private functions.
     */
    function privateFunction()
    {

    }
}

//Create an instance of the class
var myClass = new DoctaJonez.SomeClass();

//Do some stuff with the instance
myClass.publicFunction();
7

7 Answers

10
votes

For general understanding of OOP in JavaScript you can't do better than read Douglas Crockford:

For Dojo fans (and for general techniques) Neil Roberts has good articles:

Plain vanilla dojo.declare() is probably the most advanced OOP foundation in mainstream libraries around. I am biased, but don't take my word for it. Here are examples on how to use it.

A plain vanilla object:

// Let's define a super simple class (doesn't inherit anything).
dojo.declare("Person", null, {
  // Class-level property
  answer: 42,

  // Class-level object property
  name: {first: "Ford", last: "Prefect"},

  // The constructor, duh!
  constructor: function(age){
    this.age = age; // instance-level property
  },

  // A method
  saySomething: function(verb){
    console.log("I " + verb + " " +
      this.name.first + " " + this.name.last + "!" +
      " -- " + this.answer);
  },

  // Another method
  passportControl: function(){
    console.log("I am " + this.age);
  }
});

Example of use:

// A fan of Ford Perfect
var fan = new Person(18);
fan.saySomething("love"); // I love Ford Perfect! -- 42
fan.passportControl();    // I am 18

Single inheritance is easy:

// Let's create a derived class inheriting Person
dojo.declare("SuperAgent", Person, {
  // Redefine class-level property
  answer: "shaken, not stirred",

  // Redefine class-level object property
  name: {first: "James", last: "Bond"},

  // The constructor
  constructor: function(age, drink){
    // We don't need to call the super class because
    // it would be done automatically for us passing
    // all arguments to it.

    // At this point "age" is already assigned.

    this.drink = drink; // Instance-level property
  },

  // Let's redefine the method
  saySomething: function(verb){
    // Let's call the super class first
    this.inherited(arguments);
    // Pay attention: no need for extra parameters, or any extra code,
    // we don't even name the class we call --- it is all automatic.
    // We can call it any time in the body of redefined method

    console.log("Yeah, baby!");
  },

  shoot: function(){ console.log("BAM!!!"); }
});

Example of use:

// Let's create a James Bond-wannabe
var jb007 = new SuperAgent(45, "Martini");
jb007.saySomething("dig");  // I dig James Bond! -- shaken, not stirred
                            // Yeah, baby!
jb007.passportControl();    // I am 45
jb007.shoot();              // BAM!!!

// Constructors were called in this order: Person, SuperAgent
// saySomething() came from SuperAgent, which called Person
// passportControl() came from Person
// shoot() came from SuperAgent.

Mixins:

// Let's define one more super simple class
dojo.define("SharpShooter", null, {
  // For simplicity no constructor

  // One method to clash with SuperAgent
  shoot: function(){
    console.log("It's jammed! Shoot!");
  }
});

Mixin-based multiple inheritance:

// Multiple inheritance
dojo.declare("FakeAgent", ["SuperAgent", "SharpShooter"], {
  // Let's do it with no constructor

  // Redefine the method
  saySomething: function(verb){
    // We don't call super here --- a complete redefinition

    console.log("What is " + verb "? I want my " + this.drink + "!");
  },
});

Example of use:

// A fake agent coming up
var ap = new FakeAgent(40, "Kool-Aid");
ap.saySomething("hate"); // What is hate? I want my Kool-Aid!
ap.passportControl();    // I am 40
ap.shoot();              // It's jammed! Shoot!

// Constructors were called in this order: Person, SuperAgent
// saySomething() came from FakeAgent
// passportControl() came from Person
// shoot() came from SharpShooter.

As you can see, dojo.declare() gives all necessities with a simple to use API: straight single inheritance, mixin-based multiple inheritance, automatic chaining of constructors, and no-hassle super methods.

2
votes

If you (and your team) is used to Java but need to make some JavaScript for a web site, perhaps you should consider Google Web Toolkit (GWT). It lets you code JavaScript using Java, which is converted to JavaScript. I haven't tried it, though.

JavaScript is actually a quite cool language. It has a few flaws (including allowing you to do very stupid stuff), but with a little self dicipline you can make great stuff. JavaScript is actually object-oriented, not so much class-oriented, but you can do much of the same stuff. You don't have (AFAIK) inheritance, but it's not strict at all (one of its powerful but also dangerous features) with typing so you'll find it's not limiting.

1
votes

mepcotterell provides good links, but I'd like to add that I personally prefer to see namespaces as objects i.e. DoctaJonez.Namespace1 = {};.

1
votes

For example, in http://mckoss.com/jscript/object.htm.

You'll find a bunch of examples when googling for "JavaScript object-oriented". By taking a look at popular JavaScript frameworks like Ext JS you'll get a feeling for these concepts and how they're applied in practice.