Skip to content

Instantly share code, notes, and snippets.

@joelmoss
Last active December 18, 2015 06:59
Show Gist options
  • Save joelmoss/5743190 to your computer and use it in GitHub Desktop.
Save joelmoss/5743190 to your computer and use it in GitHub Desktop.
Codio JS Class proposal

Codio Javascript Class Proposal

While the Codio Client has a simple inheritance system in the form of the core/context plugin, it leaves a little to be desired and is lacking in a few areas that I feel would greatly improve the readability of our code base, as well as providing a little extra functionality.

Javascript has no such thing as Classes, but it has several different ways to fake them. We need a clean and concise way to define and use classes, with the ability for constructors, inheritance and access to overridden methods.

John Resig posted an article a long time ago with his solution for Classes in Javascript. It's simple, but powerful, and is extremely readable, so it will form the basis of this proposal.

The Base Class

Every Class is defined using Class.extend, which will give our new class the ability to have an init constructor and inherit or be inherited.

var MyClass = Class.extend({
  // The class constructor method, called when this class is initialized with `new MyClass();`.
  init: function(){
    // do something
  },
  
  // A public method.
  myMethod: function(){
    // do something else
  }
});

Nice and simple!

Public and Private Class methods.

Private methods are also non-existent in Javascript, but this Class system won't allow us to define private methods. We can of course simply define our private methods as functions outside of the class definition, but then these functions will not have access to our class, and its methods and variables.

We could expose our Class to a private function by either passing this as a function argument, or by using call() or apply(). on the function. But this requires additional work, is messy and not very elegant. We also have testing to think about. Such private functions are completely untestable as they are not available outside of the module.

Faking Private Class Methods.

Private Class methods are therefore prefixed with an underscore to easily identify their visibility, and ensure maximum testability.

var MyClass = Class.extend({
  // A public method.
  myPublicMethod: function(){
    // do something else
  },
  
  // A private method.
  _myPrivateMethod: function(){
    // do something else
  }
});

If you are not sure if a method should be private or not, think about whether it will be called from outside it's class. If it won't be, then it is private.

Every attempt should be made to use 'real' private functions, which should be defined outside the class, but please be mindful of the this context. Any function or method that requires this to be the calling class, should be defined within the class and not as a 'real' private method. This is to ensure that this is clearly identified.

Inheritance

Any Class can now easily and clearly inherit from any other class:

var Person = Class.extend({
  init: function(isDancing){
    this.dancing = isDancing;
  },
  dance: function(){
    return this.dancing;
  }
});
 
var Ninja = Person.extend({
  init: function(){
    this._super( false );
  },
  dance: function(){
    // Call the inherited version of dance()
    return this._super();
  },
  swingSword: function(){
    return true;
  }
});
 
var p = new Person(true);
p.dance(); // => true
 
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
 
// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class
@joelmoss
Copy link
Author

Ok, then looks like I've been shot down! ;) Although I disagree with the "it's not the Javascript way" argument. We should be doing it the best way that improves the code, regardless of whether it is the "Javascript way".

One note about testing private methods though... this is hard to describe until you really start writing tests. So I will leave it for now. ;)

@dignifiedquire
Copy link

I'm afraid I have one more point against this class based system. It adds new functions .extend to every object you create without any necessity of them being there. So I'm definitely in favor of using something like util.extend(child, parent);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment