Grauw’s blog
Object-oriented programming in JavaScript
A long time ago I posted about object oriented programming and creating classes in JavaScript. That being a bit outdated, and me knowing a lot more about JavaScript now, I decided to make another post on that topic.
It is possible to produce OOP class-like definitions using JavaScript functions and prototypes. What follows is a description of syntax, best practices and oddities of this. The syntax used here uses no external libraries.
Update: I changed the constructor function notation from var MyClass = function() {};
to function MyClass() {}
. The latter will have a name property set on it which is useful for debugging and on par with the native JS objects (e.g. Array.name == "Array"
). It also has the benefit of being available in the entire scope. Additionally, I removed the public properties exception.
Creating classes
JavaScript classes and methods are created in the following manner:
function MyClass() { // constructor } MyClass.prototype.myMethod = function() { // method }; MyClass.myStaticMethod = function() { // class method (also known as static method) };
Convention for class names is to start with an upper-case letter (CamelCase), and members start with a lower-case letter (camelCase).
You instantiate an object using the new
operator: new MyClass()
.
Documenting classes
Class and member documentation is created using JSDoc annotations, like so:
/** * Constructor description * @param option The first argument * @class * Class description */ function MyClass(option) { // constructor } /** * Method description * @param {Array} list The first argument * @return {boolean} The result */ MyClass.prototype.doSomething = function(list) { // method };
It is recommended to create these always. The example’s method documentation also shows optional type annotations. Primitive types are written using lowercase: number
, boolean
and string
, and object types as one would expect: MyClass
, Array
, Function
and Object
.
Creating object properties
Object properties should always be initialised in the constructor, so that you can use the constructor as a reference of which properties the object has, and so that the object is always in a defined state:
function MyClass() { this.myProperty = null; } MyClass.prototype.getMyProperty = function() { return this.myProperty; }; MyClass.prototype.setMyProperty = function(value) { return this.myProperty = value; };
Properties should generally be considered private; some people like to make this explicit by using a _
prefix. This is for reasons of encapsulation; modern JavaScript runtimes do support property getters and setters but these do not limit visibility nor do they have convenient syntax. So Java’s methodology of creating getSomething()
and setSomething()
getter/setter methods is adopted. Encapsulating internal state using accessor is essential to be able to deal with changing requirements, refactoring and performance optimisation in a straightforward manner and without compatibility problems.
Extending classes
In JavaScript you can not express inheritance directly. To inherit from another class you need a small extend()
utility function:
function MyClass() { MyBaseClass.call(this); // call super } extend(MyBaseClass, MyClass); MyClass.prototype.doSomething = function(someValue) { MyBaseClass.prototype.doSomething.call(this, someValue); // call super }; /** * Class extension utility function * @param base The base class * @param constructor The constructor function for the new class */ function extend(base, constructor) { var prototype = new Function(); prototype.prototype = base.prototype; constructor.prototype = new prototype(); constructor.prototype.constructor = constructor; }
Here, MyClass
inherits from MyBaseClass
, and MyClass
’s constructor invokes the parent object’s constructor. The doSomething()
method shows how to call a base method.
You can check whether something is an instance of a certain class using the instanceof
operator, e.g. new MyClass() instanceof MyBaseClass ? 'yes' : 'no'
.
Grauw
Comments
None.