The Closure Library makes use of theinheritance pattern, which is particularly compelling when used with the Closure Compiler . Those of you who have read JavaScript: The Good Parts by Douglas Crockford may use thefor inheritance that he espouses.

Crockford appears to object to the pseudoclassical pattern because: "There is no privacy; all properties are public. There is no access to super methods...Even worse, there is a serious hazard with the use of constructor functions. If you forget to use the new prefix when calling a constructor function, then this will not be bound to a new object...There is no compile warning, and there is no runtime warning."

This article discusses the advantages of the pseudoclassical pattern over the functional pattern. I argue that the pattern used by the Closure Library paired with the Closure Compiler removes existing hazards while I also examine the hazards introduced by the functional pattern (as defined in The Good Parts). First let me demonstrate what I mean by the functional pattern.

Example of the functional pattern

phone

smartPhone

var phone = function(spec) { var that = {}; that.getPhoneNumber = function() { return spec.phoneNumber; }; that.getDescription = function() { return "This is a phone that can make calls."; }; return that; }; var smartPhone = function(spec) { var that = phone(spec); spec.signature = spec.signature || "sent from " + that.getPhoneNumber(); that.sendEmail = function(emailAddress, message) { // Assume sendMessage() is globally available. sendMessage(emailAddress, message + "

" + spec.signature); }; var super_getDescription = that.superior("getDescription"); that.getDescription = function() { return super_getDescription() + " It can also send email messages."; }; return that; };

var myPhone = phone({"phoneNumber": "8675309"}); var mySmartPhone = smartPhone({"phoneNumber": "5555555", "signature": "Adios"}); mySmartPhone.sendEmail("noone@example.com", "I can send email from my phone!");

Example of the pseudoclassical pattern

goog.provide('Phone'); goog.provide('SmartPhone'); /** * @param {string} phoneNumber * @constructor */ Phone = function(phoneNumber) { /** * @type {string} * @private */ this.phoneNumber_ = phoneNumber; }; /** @return {string} */ Phone.prototype.getPhoneNumber = function() { return this.phoneNumber_; }; /** @return {string} */ Phone.prototype.getDescription = function() { return 'This is a phone that can make calls.'; }; /** * @param {string} phoneNumber * @param {string=} signature * @constructor * @extends {Phone} */ SmartPhone = function(phoneNumber, signature) { Phone.call(this, phoneNumber); /** * @type {string} * @private */ this.signature_ = signature || 'sent from ' + this.getPhoneNumber(); }; goog.inherits(SmartPhone, Phone); /** * @param {string} emailAddress * @param {string} message */ SmartPhone.prototype.sendEmail = function(emailAddress, message) { // Assume sendMessage() is globally available. sendMessage(emailAddress, message + '

' + this.signature_); }; /** @override */ SmartPhone.prototype.getDescription = function() { return SmartPhone.superClass_.getDescription.call(this) + ' It can also send email messages.'; };

goog.require('Phone'); goog.require('SmartPhone'); var phone = new Phone('8675309'); var smartPhone = new SmartPhone('5555555', 'Adios'}; smartPhone.sendEmail('noone@example.com', 'I can send email from my phone!');

Drawbacks to the functional pattern

Instances of types take up more memory

phone()

The following is an example in the style of the functional pattern for inheritance as explained in Douglas Crockford's. It contains the definition for atype as well as a subtypeInstances of each of these types could be created and used as follows:Here is the same logic as the previous example, only written using Closure's style and coding conventions.Similarly, here is an example of how these types could be used:Every timeis called, two new functions are created (one per method of the type). Each time, the functions are basically the same, but they are bound to different values.

These functions are not cheap because each is a closure that maintains a reference for every named variable in the enclosing function in which the closure was defined. This may inadvertently prevent objects from being garbage collected, causing a memory leak. The Closure Library defines goog.bind() and goog.partial() in base.js to make it easier to create closures that only maintain the references they need, making it possible for other references to be removed when the enclosing function exits.

This is not a concern when Phone() is called because of how it takes advantage of prototype-based inheritance. Each method is defined once on Phone.prototype and is therefore available to every instance of Phone . This limits the number of function objects that are created and does not run the risk of leaking memory.

Methods cannot be inlined

// phone1 and phone2 are of type Phone var caller = phone1.getPhoneNumber(); var receiver = phone2.getPhoneNumber(); operator.createConnection(caller, receiver);

operator.createConnection(caller.phoneNumber_, receiver.phoneNumber_);

Superclass methods cannot be renamed (or will be renamed incorrectly)

When possible, the Compiler will inline methods, such as simple getters. This can reduce code size as well as improve runtime performance. Because the methods in the functional pattern are often bound to variables that cannot be referenced externally, there is no way for the Compiler to rewrite method calls in such a way that eliminates the method dispatch. By comparison, the following code snippet:could be rewritten to the following by the Compiler:When the Closure Compiler is cranked up to 11, one of the heuristics it uses for renaming is that any property that is not accessed via a quoted string is allowed to be renamed, and the Compiler will do its best to rename it. All quoted strings will be left alone. It is not required to use the Compiler with this aggressive setting, but the potential reduction in code size is too big to ignore.

From the phone example, getDescription is used both as a property defined on that and as a string literal passed to that.superior() . If aggressive renaming were turned on in the Compiler, getDescription would have to be used as a quoted string throughout the codebase so that it did not get renamed. (It could also be declared as an extern, which is what prevents built-in method names, such as toString() from being renamed, but because there is no function to associated the method with, it would have to be declared as an extern on Object.prototype .) Remembering to refer to it via a string literal throughout the codebase is a bear and precludes the benefits of aggressive renaming. (To be fair, some of the constructs in the candidate spec for EcmaScript 5, such as Object.defineProperty() , have similar issues. The solution will likely be to add logic to the Compiler to treat Object.defineProperty() in a special way. The same could be done for superior() if one were so motivated.)

Types cannot be tested using instanceof

instanceof

phone

smartPhone

Because there is no function to use as the constructor, there is no appropriate argument to use with the right side of theoperator to test whether an object is aor a. Because it is common for a function to accept multiple types in JavaScript, it is important to have some way to discern the type of the argument that was passed in.

An alternative would be to test for properties that the desired type in question may have, such as:

if (arg.sendEmail) { // implies arg is a mobilePhone, do mobilePhone things }

sendEmail

arg

mobilePhone

desktopComputer

sendEmail

if (arg instanceof MobilePhone)

Encourages adding properties to Function.prototype and Object.prototype

Function.prototype.method

Object.method

superior

Object.prototype

There are two problems with this solution. The first is that checking for theproperty is only a heuristic -- it does not guarantee thatis a. Perhaps there is also a type calledthat also has amethod that would also satisfy the above test. The second problem is that this code is not self-documenting. If the conditional checked, it would be much clearer what was being tested.In Chapter 4 of, Crockford introducesand uses it in Chapter 5 viato add a property namedtoto aid in creating superclass methods. Adding properties to fundamental prototypes makes it harder for your code to play nicely with other JavaScript libraries on the page if both libraries modify prototypes in conflicting ways.

The Google Maps team learned this the hard way when they decided to add convenience methods to Array.prototype , such as insertAt (incidentally, this is exactly what Crockford does in Chapter 6). It turned out that many web developers were using for (var i in array) to iterate over the elements of an array (as opposed to using for (var i = 0; i < array.length; i++) as they should have been). The for (var i in array) syntax includes properties added to Array.prototype as values of i , so bringing in the Google Maps library would break the code on those web pages. Rather than trying to change web developers' habits, the Maps team changed their library. It is for reasons such as these that array.js in Closure is a collection of array utility functions that take an array as their first argument rather than a collection of modifications to Array.prototype .

For those of you who do not own Crockford's book, here is the code in question. Try running the following and see what happens:

// From Chapter 4. Function.prototype.method = function(name, func) { this.prototype[name] = func; return this; }; // From Chapter 5. Object.method('superior', function(name) { var that = this, method = that[name]; return function() { return method.apply(that, arguments); }; }); // Create a new object literal. var obj = { "one": 1, "two": 2 }; // Enumerate the properties of obj. for (var property in obj) alert(property);

obj

one

two

superior

superior

Makes it impossible to update all instances of a type

Instead of enumerating two properties in, three are listed:, and. Now every object literal in your program will also have a property named. Though it may be handy for objects that represent classes, it is inappropriate for ordinary record types.In the Closure model, it would be possible to add a field or method to all instances of a type at any point in the program by adding a property to the function constructor's prototype. This is simply not possible in the functional model.

Although this may seem like a minor point, it can be extremely useful when developing or debugging a system to redefine a method on the fly (by using a REPL such as Chickenfoot or the Firebug console). This makes it possible to put probes into a running system rather than having to refresh the entire web page to load changes.

Naming newly created objects is awkward

var phone = new Phone('8675309');

function callJenny() { var phone = phone('8675309'); makeCall(phone.getPhoneNumber()); }

phone

phone()

callJenny()

phone

undefined

'8675209'

my

Results in an extra level of indentation

Potential objections to the pesudoclassical pattern

Won't horrible things happen if I forget the new operator?

@constructor

new

new

Didn't Crockford also say I wouldn't have access to super methods?

superClass_

goog.inherits(SmartPhone, Phone)

super_getDescription

Won't all of the object's properties be public?

@private

Won't declaring SomeClass.prototype for each method and field of SomeClass waste bytes?

SomeClass.prototype

SomeClass.prototype = { getFoo: function() { return this.foo_; }, setFoo: function(foo) { this.foo_ = foo; }, toString: function() { return '<foo:' + this.getFoo() + '>'; } };

I don't need static checks -- my tests will catch all of my errors!

This may be more of a personal preference, but the "capitalize constructor functions" convention makes it fairly intuitive to name a newly created object. From the pseudoclassical example, we have:where the name of the variable matches that of the constructor, but has a lowercase letter. If the same thing were done in the functional case, it could cause an error:Here the local variableshadows the function, sowill throw an error when called becauseis bound towhen it is applied to. Because of this, it is common to add an arbitrary prefix, such as, to the variable name for newly created objects when using the functional pattern.Again, this may be more of a personal preference, but requiring the entire class to be defined within a function means that everything ends up being indented one level deeper than it would be when using the Closure paradigm. I concede that this is how things are done in Java, and C# even suggests adding an extra level of depth for good measure with its namespaces, so maybe there's some prize for hitting the tab key a lot that no one told me about. Regardless, if you have ever worked someplace (like Google) where 80-character line limits are enforced, it's nice to avoid line-wrapping where you can.If a function with theannotation is called without theoperator, the Closure Compiler will emit an error. (Likewise, if theoperator is used with a function that does not have the annotation, it will also throw an error.) Crockford's objection that there is no compile-time warning no longer holds! (I find this odd because Crockford could have created his own annotation with an identical check in JSLint.)Yes, but as the example above demonstrates, a super class's methods are accessible via theproperty added to a constructor function. This property is added as a side-effect of calling. Unlike the functional example with, super class accessors do not need to be explicitly created in Closure.It depends on what you mean by "public." All fields and methods of an object marked with theannotation will be private in the sense that the Compiler can be configured to reject the input if a private property is being accessed outside of its class. So long as all of the JavaScript in your page is compiled together, the Compiler should preclude any code paths that would expose private data.Not really. The Compiler will create a temporary variable forand reuse it. As the Compiler works today, it is admittedly most compact to write things in the following style:However this style has some drawbacks. Doing the above introduces an extra level of indenting and makes reordering methods more tedious because extra care is required to ensure that the last property declared does not have a trailing comma and that all of the other properties do. I think that it is reasonable to expect the Compiler to produce output more similar to the above in the future, but that the recommended input will continue to match the style exemplified in the pseudoclassical example Let's be honest -- do you write tests? And if you are writing tests, how much confidence are they giving you about your code's correctness? As I've discussed previously , existing tools for testing web applications make it difficult to write thorough tests. So even if you have taken the time to write tests, it is unlikely that they exercise all of your code. (Lack of good tools for measuring code coverage by JavaScript tests contributes to the problem.)

By comparision, the Closure Compiler examines your entire program and provides many compile-time checks that can help you find errors before running your code. If Douglas Crockford claims that JSLint will hurt your feelings, then the Closure Compiler will put you into therapy.

"I never knew how sloppy my JavaScript was until I started using the Closure Compiler.

Good grief!"