This article is obsolete. For current information, see OP and OOP and OP Examples (also on menu above). Some statements ("Yes, JavaScript inheritance is prototypal,...") are just wrong. (See Prototypes also on menu above.) This shows how completely the prevailing wisdom had substituted for clear thinking on this topic.

JavaScript: A New View

© 2013, Martin Rinehart

JavaScript has been chosen as the leading language for Gnome applications. (Gnome is one of the two leading Linux windowing systems) As a confirmed JavaScript lover I was delighted to read about it. However, reading the comments from JavaScript-ignorant developers was distressing.

There were all the usual misconceptions: JS is a toy language for scripting, you can't do OOP and so on. We're all used to those. In fact, and sadly, we're all used to those comments from developers who should know better than to make pronouncements about languages they've never tried. What's distressing, however, is that it's really our fault. We've all been wrong about JavaScript, and for too long.

It Ain't Prototypal

Yes, JavaScript inheritance is prototypal, of course. What is not prototypal is the fundamental difference between class-based OOP (as in C++ and Java) and JavaScript. JavaScript's unfamiliar inheritance scheme is interesting, but almost irrelevant.

Inheritance? Who Needs It?

The "big 3" determinants of OOP are inheritance, encapsulation and... Well, you supply another. Few would omit inheritance in such a list. I respectfully disagree.

The Gang of Four (GoF) recommend composition over inheritance. JavaScript guru Doug Crockford tells us to keep our inheritance chains short. Many of us (myself included) wrote our first JavaScript with no inheritance at all. Learning about prototypal inheritance was on the "to do" list but getting some website working came first.

Most of us know from first-hand experience that you can write JavaScript without understanding the prototypal inheritance model. But what happens when we educate ourselves?

Mastering Prototypal Inheritance

A couple years back I dove into inheritance in JavaScript in a big way. See this article and the next four, plus the Master Classers section of my website.

Rethinking Inheritance

To summarize what I gained from studying the masters, (Crockford, Edwards, Flanagan and Ressig in my sample): I learned to write perfectly good, inheritance-rich JavaScript. If I chose not to use inheritance, it was no longer from ignorance. What did I choose?

Go back up to the root page in that section of my site. Go where it says, in a highlighted Post Script box, that JS inheritance is "unimportant if you want to write good, object-oriented JavaScript." The more JavaScript I write, the more convinced I become that inheritance, in JavaScript, is unimportant.

As a small experiment I took a medium-sized bit of JavaScripting that was on top of my priority stack and decided to write it without inheritance. In my GoF/Crockford style it would have had some, but not too much, inheritance. I wrote it with none. Conclusion: a couple minor parts would have been better, but only a little better, with inheritance.

Does JavaScript Need OOP?

My JavaScript consists of a small library of functions and lots and lots of classes. Internally my code is object-oriented. My code is more object-oriented now in JavaScript than it ever was in Java. (If you don't know Java, it was far too OOP! Everything in Java is a class or an instance of a class.) That led me to ask, why?

Object Programming Is Not OOP

Let's draw a distinction between OOP and object programming. OOP is what we know and love about C++, Java and so on. These languages have been extremely successful. The speed with which C++ overtook C was remarkable testimony to the power of OOP. But there is more to object-orientation than OOP.

The "more" in JavaScript is the fact that classes are objects and objects are programmable. An object is a bundle of named values. In C++ or Java you can program with those values, but you cannot program with the names. (Yes, introspection gives you the beginnings of object programming, but only in a kludgy way.)

In object programming we routinely program with both the names and the values. I find the ability to program objects far more important than the ability to extend classes via inheritance. In fact (GoF lovers rejoice!) the ability to do object programming makes most inheritance unnecessary.

Do Class-Based Languages Need Object Programming?

Empatically, yes! That is an assertion I make from graduating from class-based programming to true object programming. I cannot, however, prove it. What we need is a C++ or Java extension that adds object programming to one of these languages. I predict it would catch on faster than C++ caught on in the C community.


Object Programming: Examples

Let's look at examples from the interface of JavaScript to the browsers' DOM, Document Object Model. In the DOM, one object is the root (sort of) and the rest of what you see in your browser's client area are objects, nodes of a tree branching from the root. These objects have many properties, including a style property. That property itself is an object with its own properties.

Programming the Style Object

You could have a border color style. (And a width, and a style.borderStyle, such as 'solid', 'dashed' and so on). You could have separate styles for borderLeft, borderTop and so on. You could have a background style, possibly a color or an image. If you have an image you could have it repeat vertically, horizontally, both or neither. The possibilities go on. Altogether than are hundreds of styles possible for each object in the DOM, and hundreds of DOM elements can make up a single page. What to do?

In a class-based language you could start with a basic set of styles and then extend the basic set to incorporate clusters of styles commonly used together. Alternative, you could have a single style class that had a property for every one of the hundreds of possibilities. (Alternatively, and more reasonably, you could forget the OOP model and use some other structure to hold styles and their values, such as a hash table.)

But if you had an object programming capability you could just add styles to a DOM object as you needed them. Need a separate color for the top border? obj.style.borderTopColor = .... (Python programmers know and use this sort of dynamic object.)

A Program to Add Properties

This is a general-purpose, illustrative program to add properties to objects as needed:

function add_property( object, prop_name, prop_value ) {
    object[ prop_name ] = prop_value;
}

Of course, since it is a one-liner it is really easier to just use the language:

object[ prop_name ] = prop_value;

    // just as simple as

add_property( object, prop_name, prop_value );

A Program to Add Objects

Assume that you have two objects. The first has the default styles for links, for example. The second has non-default styles that you would like to apply to a particular subset of the links on a page. Wouldn't it be nice if we could just add the properties from one object to the properties of another? This will do the trick:

function add_props( default, special ) {
    for ( var prop_name in special ) { default[ prop_name ] = special[ prop_name ]; }
}

A Safer Program to Add Objects

I do hope the above example scares you, at least a little. It modifies the default object directly, a side-effect. (In Ruby you would add "!" as a suffix tothe name: add_props!().) Side effects are not considered a best practice in many circles. Let's create a new object and leave the originals untouched.

function add_objects ( base, addendum ) {
	var ret = {}; // create a new object
	for ( var prop_name in base ) { ret[ prop_name ] = base[ prop_name ]; }
	for ( prop_name in addendum ) { ret[ prop_name ] = addendum[ prop_name ]; }
	return ret;
}

That function creates the union of base and addendum. In the intersection of the two, the property values from addendum overwrite the values from base. It is similarly easy to create other utilities that preserve base or return only the intersection, the union minus the intersection or whatever. In fact, there is no general library of such functions as they are easier to type into your source than to look up in a library reference.

Reversing the Dictionary

In JavaScript, an object is a dictionary. (Just as Perl proved with regex, once you bring a structure to the front of the class in a language, it becomes much more heavily used.) The value of foo.bar is the value found by looking up 'bar' in the foo dictionary. The JavaScript dictionary is coded for fast lookups (probably a hash table). Assume that we have an object where we want to lookup the property name based on its value. Reversing the values and keys would be helpful. Try this:

function reverse( object ) {
    ret = {}; // new, empty object
    for ( var prop_name in object ) } ret[ object[prop_name] ] = prop_name; }
    return ret;
}

Let's try this out, and, while we do so, illustrate the value of the JavaScript object literal for those who have not used it.

var pets = { dog:'Fido', cat:'Tiger', python:'Monty' };
// pets.dog == pets[ 'dog' ] == 'Fido'

var by_name = reverse( pets );

/* by_name is:
    { Fido:'dog', Tiger:'cat', Monty:'python' }

 by_name.Fido == 'dog'
 by_name[ 'Tiger' ] == 'cat' */

Defining Object Programming

Wikipedia defines "objects" in "object-oriented programming" as "data structures together with their associated processing routines." These are the objects that C++ and Java manipulate. In JavaScript they are the values of the properties (the definiens of the definiendum/definiens pairs) of the dictionary.

"Object programming" as used here describes the ability to program with equal facility with both the definienda and the definiens. An object programming language is one that provides syntax for these:

(Having the ability to create library routines that perform these operations does not meet these criteria—Fortran and Basic are not object programming languages. To call a language an "object programming" language, these operations must be part of the syntax, available through statements, not function calls.)

By this definition, JavaScript is a nearly complete object-programming language. It lacks only the ability to modify the the definienda directly. (In JavaScript, this does half the job: dict[ new_name) ] = dict[ old_name ];. You then need to delete dict[ old_name ] to "modify" the definiendum.)

Conclusion

The classes in languages like C++ and Java are not objects. If they were, these languages would be suitable for object programming (and would be far more expressive). JavaScript, on the other hand, has no non-programmable constructs. Everything is an object and the objects can be used in programs just as easily as other languages can use the values of object properties.

It is this native ability to do fluent object programming that makes JavaScript so powerful. It makes inheritance quite unimportant, although it's there if you like. We JavaScript converts need to start to spread the object programming gospel so the uninformed victims of limited, class-based languages begin to learn that it is they, not us, who are using unnecessarily restricted tools.


P. S. To complete my own study of inheritance, I am now building a system using inheritance as if JavaScript were Java or C++, using moderately long inheritance chains. I am not done but the preliminary report is this: it's bad practice but it's not as bad as I had feared. (I picked a trial system that was particularly amenable to inheritance, however. Even with the deck stacked, my conclusion is unchanged: inheritance is a nice little feature that you don't really need if you have object programming.)

P. P. S. JavaScript is also limited in that it permits only strings as definienda in its dictionaries. I chose to ignore this in the definition of "object programming" as the limitations of the objects and the programmability of the objects are really two separate issues. This does not mean I don't object to this limitation. JavaScript would be more fun if it permitted all its data types to be used as definienda. I chose to say "definiendum" (and "definienda"), not "name" (and "names"), in the hopes that we might some day go beyond just strings.

Feedback: MartinRinehart at gmail dot com

# # #