Thursday, January 3, 2013

JavaScript Interfaces


The interface is one of the most useful tools in the object-oriented JavaScript programmer’s toolbox. The first principle of reusable object-oriented design mentioned in the Gang of Four’s Design Patterns says “Program to an interface, not an implementation,” telling you how fundamental this concept is.

The problem is that JavaScript has no built-in way of creating or implementing interfaces. It also lacks built-in methods for determining whether an object implements the same set of methods as another object, making it difficult to use objects interchangeably. Luckily, JavaScript is extremely flexible, making it easy to add these features.

However, using interfaces is not entirely without drawbacks. JavaScript is an extremely expressive language, in large part because it is loosely typed. Using interfaces is a way of partially enforcing strict typing. This reduces the flexibility of the language. Using any interface implementation in JavaScript will create a small performance hit, due in part to the overhead of having another method invocation. The biggest drawback is that there is no way to force other programmers to respect the interfaces you have created. In other languages, the concept of the interface is built-in, and if someone is creating a class that implements an interface, the compiler will ensure that the class really does implement that interface. In JavaScript, you must manually ensure that a given class implements an interface. You can mitigate this problem by using coding conventions and helper classes, but it will never entirely go away.

Pro Javascript Design Patterns book explores three ways of emulating interfaces in JavaScript:
  • comments, 
  • attribute checking, and 
  • duck typing. 
No single technique is perfect, but a combination of all three will come close.

Describing Interfaces with Comments

The easiest and least effective way of emulating an interface is with comments. Mimicking the style of other object-oriented languages, the interface and implements keywords are used but are commented out so they do not cause syntax errors. Here is an example of how these keywords can be added to code to document the available methods:

This doesn't emulate the interface functionality very well. There is no checking to ensure that CompositeForm actually does implement the correct set of methods. No errors are thrown to inform the programmer that there is a problem. It is really more documentation than anything else. All compliance is completely voluntary. 

That being said, there are some benefits to this approach. It’s easy to implement, requiring no extra classes or functions. It promotes reusability because classes now have documented interfaces and can be swapped out with other classes implementing the same ones. It doesn't affect file size or execution speed; the comments used in this approach can be trivially stripped out when the code is deployed, eliminating any increase in file size caused by using interfaces. However, it doesn't help in testing and debugging since no error messages are given.

Emulating Interfaces with Attribute Checking

The second technique is a little stricter. All classes explicitly declare which interfaces they implement, and these declarations can be checked by objects wanting to interact with these classes. The interfaces themselves are still just comments, but you can now check an attribute to see what interfaces a class says it implements:


In this example, CompositeForm declares that it implements two interfaces, Composite and FormItem. It does this by adding their names to an array, labeled as implementsInterfaces. The class explicitly declares which interfaces it supports. Any function that requires an argument to be of a certain type can then check this property and throw an error if the needed interface is not declared.

There are several benefits to this approach. You are documenting what interfaces a class implements. You will see errors if a class does not declare that it supports a required interface. You can enforce that other programmers declare these interfaces through the use of these errors. The main drawback to this approach is that you are not ensuring that the class really does implement this interface. You only know if it says it implements it. It is very easy to create a class that declares it implements an interface and then forget to add a required method. All checks will pass, but the method will not be there, potentially causing problems in your code. It is also added work to explicitly declare the interfaces a class supports.

Emulating Interfaces with Duck Typing

In the end, it doesn't matter whether a class declares the interfaces it supports, as long as the required methods are in place. That is where duck typing comes in. Duck typing was named after the saying, “If it walks like a duck and quacks like a duck, it's a duck.” It is a technique to determine whether an object is an instance of a class based solely on what methods it implements, but it also works great for checking whether a class implements an interface. The idea behind this approach is simple: if an object contains methods that are named the same as the methods defined in your interface, it implements that interface. Using a helper function, you can ensure that the required methods are there:

This differs from the other two approaches in that it uses no comments. All aspects of this are enforceable. The ensureImplements function takes at least two arguments. The first argument is the object you want to check. The other arguments are the interfaces that the first object will be compared against. The function checks that the object given as the first argument implements the methods declared in those interfaces. If any method is missing, an error will be thrown with a useful message, including both the name of the missing method and the name of the interface that is incorrectly implemented. This check can be added anywhere in your code that needs to ensure an interface. In this example, you only want the addForm function to add the form if it supports the needed methods.

While probably being the most useful of the three methods, it still has some drawbacks. A class never declares which interfaces it implements, reducing the reusability of the code and not self-documenting like the other approaches. It requires a helper class, Interface, and a helper function, ensureImplements. It does not check the names or numbers of arguments used in the methods or their types, only that the method has the correct name.

Pro Javascript Design Patterns book is using a combination of the first and third approaches. Authors use comments to declare what interfaces a class supports, thus improving reusability and improving documentation. Also, authors use the Interface helper class and the class method Interface.ensureImplements to perform explicit checking of methods. They return useful error messages when an object does not pass the check.

Here is an example of the Interface class and comment combination:

Interface.ensureImplements provides a strict check. If a problem is found, an error will be thrown, which can either be caught and handled or allowed to halt execution. Either way, the programmer will know immediately that there is a problem and where to go to fix it.

And here is the  Interface class that we use it the above example (Interface.js):

As you can see, it is very strict about the arguments given to each method and will throw an error if any check doesn't pass. This is done intentionally, so that if you receive no errors, you can be certain the interface is correctly declared and implemented.

Another example using Interface class in Pro Javascript Design Patterns book is as follows:

Imagine that you have created a class to take some automated test results and format them for viewing on a web page. This class's constructor takes an instance of the TestResult class as an argument. It then formats the data encapsulated in the TestResult object and outputs it on request. Here is what the ResultFormatter class looks like initially:



This class performs a check in the constructor to ensure that the argument is really an instance of TestResult; if it isn't, an error is thrown. This allows you to code the renderResults method knowing confidently that the getDate and getResults methods will be available to you. Or does it? In the constructor, you are only checking that the resultsObject is an instance of TestResult. That does not actually ensure that the methods you need are implemented. TestResult could be changed so that it no longer has a getDate method. The check in the constructor would pass, but the renderResults method would fail.


The check in the constructor is also unnecessarily limiting. It prevents instances of other classes from being used as arguments, even if they would work perfectly fine. Say, for example, you have a class named WeatherData. It has a getDate and a getResults method and could be used in the ResultFormatter class without a problem. But using explicit type checking (with the instanceOf operator) would prevent any instances of WeatherData from being used.


The solution is to remove the instanceOf check and replace it with an interface. The first step is to create the interface itself:


This line of code creates a new instance of the Interface object. The first argument is the name of the interface, and the second is an array of strings, where each string is the name of a required method. Now that you have the interface, you can replace the instanceOf check with an interface check:

The renderResults method remains unchanged. The constructor, on the other hand, has been modified to use ensureImplements instead of instanceOf. You could now use an instance of WeatherData in this constructor, or any other class that implements the needed methods. By changing a few lines of code within the ResultFormatter class, you have made the check more accurate (by ensuring the required methods have been implemented) and more permissive (by allowing any object to be used that matches the interface).