Aymeric on Software

Because we needed another of these blogs...

A JavaScript Object Oriented Programming Technique

There are many conflicting approaches to object oriented programming in JavaScript. On the one hand, the language was designed with prototypal object oriented programming in mind, with the only built-in mechanism for inheritance being object inheritance. However the language is also fitted with a new keyword of dubious quality which shows aspects of a more traditional class based OO programming.

Douglas Crockford presented in his book JavaScript: The Good Parts one of the earliest techniques of consistent OO programming. However I found it quite outdated, after some of research and experimentation, I came up with the following technique which I now use in Exposition.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Namespace
var ph = ph || {};
ph.barthe = ph.barthe || {};

// Use strict header
(function() {
"use strict";

// Class declaration
ph.barthe.MyClass = function(ctr_param) {
	
	// Remap this
	var self = this;

	// Private variable
	var m_private_var;

	// Private method
	var privateMethod = function(param) {
		// ...
	};

	// Public method
	self.publicMethod = function(param) {
		// ...
	};

	// Constructor body
	(function() {
		// Temporary variable i, does not leak
		for (var i=0; i<ctr_param; ++i)
		   m_private_var += privateMethod(i);
		self.publicMethod('stuff');
	})();
};

// Object usage
var ph.barthe.exampleUsage = function() {
	var my_instance = new ph.barthe.MyClass(15);
	return my_instance.publicMethod('other stuff');	
};

// Use strict footer
})();

In the previous code sample, I employed the following techniques:

  • Use pseudo namespaces to avoid cluttering the global namespace and avoid potential naming conflicts with third party scripts. The namespace is in reality a single global object to which properties are appended. The OR operator in var ph = ph || {}; is used to make sure the object is only created if it does not already exist. This makes the code tolerant to changes in the order <script> statements.

  • Use ECMAScript 5 strict mode. This is what the seemingly useless "use strict" statement is about. Instead of adding the statement to every function, I create an anonymous function whose scope is the entire file, and execute it immediately in the static context.

  • Use “classical” OO programming with constructor functions instead of prototypes. I am more familiar with classical OO programming and the upcoming ECMAScript 6 is going to add support for classes. But a more pragmatic reason for that choice, is that relying on closures within constructor functions, appears to be the only known technique to get private members in JavaScript.

  • Use the new keyword instead of Object.create or some kind of custom make function. I think it signals my intent to use classical OO programming more clearly. The ECMAScript 5 strict mode fixes the main argument Crockford uses against the “new” keyword. In non-strict mode, if you forget to use new when you invoke a constructor function, this ends up pointing to the global context instead of the object itself. This can lead to silent failures of disastrous consequences. In strict mode, an exception is raised instead, making the mistake obvious. In addition, naming conventions enforced by JSHint and JSLint help mitigate this risk.

  • Use self = this to avoid the confusing remapping of this. This article illustrates how this is dynamically remapped and why we need to keep a reference to the original value. This is a variant of the that = this technique also mentioned by Crockford. I prefer self because I am familiar with ObjectiveC and this and that look too similar to my eyes.

  • Use an anonymous function for the constructor body. Otherwise, temporary variables can leak to clutter the constructor closure forever. I believe this pattern also increase the readability of the code, by restricting statements outside the constructor body to mere assignments. This reduces the amount of code to scan.