Op v3 Preview
Op v3 Preview
Op v3 Preview
Object Programming
Preview Edition
Preview Edition
For the full book:
Amazon ( http://www.amazon.com/JavaScript-
Inheritance-Object-Programming-
Rinehart/dp/1490463046 )
The CreateSpace eStore (
http://www.createspace.com/4327336, preview
edition discount: MAMMBM3G )
The extended eBook from Software
Developer's Journal (
http://sdjournal.org/javascript-inheritance-and-
object-programming-ebook/ )
JavaScript Inheritance and
Object Programming
Martin Rinehart
Copyright 2013, Martin Rinehart
Ebook published by Software Developer's Journal.
Print book printed on demand (POD) by
CreateSpace, a subsidiary of Amazon. Designed
and written by the author in the beautiful Hudson
Valley, New York, USA.
Versions 2e and 2p completed 9 July, 2013.
i
JS Inheritance and OP
ii
A Note for the Implementers
JavaScript, or more exactly, the subset of JavaScript Crockford
identifies as The Good Parts, is a beautiful language. It is
small, yet expressive. It's combination of C with functional
programming and object programming gives it extraordinary
depth. In nearly a half century of programming I have used
dozens of languages. Only two of them, JavaScript is one, have
been languages I've loved.
Today there are people working to free JavaScript from the
browser, to further empower JavaScript (FileWriter and WebGL,
to mention personal favorites) and to bring it up to professional
speed. My apologies to the latter group. In many ways, object
programming is the enemy of compiled speed.
So a word of encouragement and advice to our courageous
implementers. First, making JavaScript run at some reasonable
fraction of C's speed is a magnificent goal. More power to you!
(And yes, that's self-serving. You are giving more power to all of
us who write JavaScript. We love it and we thank you for it.)
Second, removing object programming to gain speed cuts out the
heart to save the patient. Object programming is not your enemy,
it is the essence of the language. Look on it as a challenge, as the
Everest of your profession. The view from the top will be
spectacular. Object programming at half the speed of C will be
breathtaking.
Martin Rinehart, 8 June 2013
Hudson Valley, New York
Website
This book is the sixth knowit at the author's website,
MartinRinehart.com. From the home page, click Knowits and
then JIOP.
The gateway page holds the notes (both footnotes and
bibliography). Hyperlinks are inline in the eBook, online in the
printed book (so the printed text of this book is uninterrupted,
and so you can click on the references).
From the gateway page, sub menus link you to the User Guide
to the JSWindows system, the engineer's reference material and
the source code.
Introduction
Within the JavaScript community there is a great deal of
misinformation regarding inheritance. Some comes from object-
oriented programmers (C++ and its offspring like Java and C#)
looking for, and not finding, their familiar classes. Some comes from
JavaScript programmers looking for Self-style prototypal
inheritance, which JavaScript's prototypes are not very good at.
In this small volume we begin at the beginning, discussing objects,
their place in software and the benefits we expect from them. We
continue to first define terms like class (three meanings) and
inheritance. With a common terminology we then look at how
class-based and prototypal inheritance can be implemented in
JavaScript. To leap ahead, we will propose ways in which JavaScript
is best served by minimizing the long inheritance chains associated
with object-oriented programming languages.
1
2 Introduction
5
6 1 Objects
Objects Do Methods
First, the syntax has things doing things just as happens outside of
the world of software. The things objects do are small software
programs, functions that the object can perform, commonly called
methods. If you program a dog (object) to speak (method) you
express it directly:
dog.speak(); // says Woof, woof
If your parrots and kittens use different methods for speaking, object
systems will choose the appropriate method for you. For those who
are academically inclined, the eBook version's Chapter 8 explains
subtype polymorphism, the principle underlying the selection of
object-appropriate methods.
Event-Driven Programming
Second, few programs now do anything except by user direction.
Most programs paint an interface (menus, icons, buttons) and wait
for a user command. This is called event-driven programming.
When the user clicks the save icon, the user's document is written
to disk. Internally, the user action could trigger a very small program:
user_data.save();
Class-Based v. Prototypal
Objects come in many guises. We will be using class-based object-
oriented programming (OOP, based on classes) and JavaScript's
hybrid class/prototypal object model.
Object systems go back to Simula and SmallTalk, in the late '70s.
These found the mainstream when Bjarne Stroustrup, at Bell Labs,
wrote a compiler that output programs in plain C from an object-
enhanced form he called C++. (During the '80s, C was the dominant
language for professional programming on non-IBM mainframes and
almost all minicomputers and microcomputers.) C++ was first
available in 1983. By the end of the decade it had become
ubiquitous.
To add objects to C, Stroustrup made some sacrifices. His enhanced
C used class modules (more on these shortly) that were not objects,
but that defined objects. Despite protests from purists, Stroustrup's
limited features were well chosen and programmers were delighted
with its improvements over original C. Other languages, such as Java
(1995) adopted the C++ object model. Programming in C++ and its
progeny is called object-oriented programming or class-based
(aka classical) OOP.
8 1 Objects
Objects Up Close
An object is a collection of properties (often a set, but set has a
mathematical meaning we do not want here). Properties are named
values. Values may be, depending on the language, simple values
(boolean, integer, character), composite values built from other
values (arrays, objects) or, in languages capable of functional
programming, functions or other blocks of code. (JavaScript also
implements functional programming borrowed from the Scheme
language, a dialect of Lisp.)
Some authors use the word property to specifically mean what we
call data propertiesproperties that are not methods. We find this
misleading in a language where functions are first-class objects.
JavaScript Inheritance and Object Programming 9
Data Properties
Objects may have data properties. These are often said to describe an
object's state. A dog might have properties such as name, breed
and date-of-birth. Each dog (called an object instance or, in
class-based OOP, an instance of the dog class) will have space
allocated to store each of these properties' values. The key point is
that each instance has its own set of data properties.
Listing 1-2
collie.speak(); // My name is Lassie.
Introducing JSWindows
The result you see in Figure 1-1 takes exactly four lines of JavaScript
code. One creates the page title and three create the three windows.
(Is there a law that says windows must be rectangles?)
The gateway to the online portion of this book is
http://www.martinrinehart.com/frontend-
engineering/knowits/op/knowits-op.html. You can use the system
your self (and enjoy the full color) by clicking Using JSWindows
from the gateway page. Let's take a look.
JavaScript Inheritance and Object Programming 11
Figure 1-1
The shield in the center of Figure 1-1 is, as you can see from the
motto, the frontend engineers' family crest. As you can see from the
buttons on its upper right, it is also a window. You can close,
maximize, restore and minimize with these buttons (right to left).
The title is also a drag handle.
JSWindows is written in JavaScript for applications on all devices
that run HTML4 or 5 and CSS2 or 3. The shapes here are done with
CSS3 border radii.
12 1 Objects
Figure 1-2
In Figure 1-2 we've changed the size of the shield, eliminated the
border radii specifications from each window and changed the two
inner windows from Window_M (window, movable) to
Window_M_BS (window, movable with buttons for sizing).
Note that there are, by default, three intermediate sizes (between min
and max), not just the single restored size of some other systems.
We are also using the CSS3 RGBA (transparency) capability for the
#2 window.
JavaScript Inheritance and Object Programming 13
Figure 1-3
Figure 1-3 is exactly two button clicks away from Figure 1-2. Look
at the sizing buttons. We clicked the large button for one small
window, the small button for the other.
Next we go on to minimizing. Note that we are minimizing windows
within their containers. The shield (the one with the motto) is
contained within SCREEN. The two smaller windows are contained
within the shield.
14 1 Objects
Figure 1-4
Notice that the minbox (Figure 1-4, holding the two minimized
windows) also has a restore (now disabled) and a minimize sizing
button. If you click its minimize button, the minbox is reduced to a
one-pixel-tall box, topped by its own sizing buttons, taking almost no
screen real estate.
But let's return to the windows with the CSS3 border radii. They're
more fun.
JavaScript Inheritance and Object Programming 15
Figure 1-5
In Figure 1-5 the original windows are shown, except that the two
smaller ones are still sizable. Here their large buttons have been
clicked.
16 1 Objects
Figure 1-6
In Figure 1-6, we clicked the maximize button of the translucent
window. (If you compare with Figure 1-5, you can see that the
Window_M Rules! window is masked.)
Isn't this the way you would have coded maximize? (It's easier
than you might guess. It works inside circles and ovals, as well as
shields, too.)
JSWindows is more fun, and in full color, when you try it online
http://www.martinrinehart.com/frontend-
engineering/knowits/op/knowits-op.html.
JavaScript Inheritance and Object Programming 17
Built-Ins
Programmers new to JavaScript quickly learn that there are common
needs that are met by built-in JavaScript objects. For example,
common mathematical operations are performed by the Math
object's methods.
Math
You want to round a number to the nearest integer. Listing 2-1 shows
an example.
19
20 2 JavaScript Objects
Listing 2-1
var width =
content_width + padding + border_width;
Date
The Date constructor returns real objects, time stamps that include
both date and time to the nearest millisecond. The Date also
provides the methods you want to manipulate dates (to set a time for
an appointment next week, for example). The bit of code in Listing
2-2 might be included when you were comparing the running times
of alternative functions.
Listing 2-2
var start = new Date();
var result = sample_long_function();
elapsed = start new Date();
Ex Nihilo Objects
In JavaScript, you can create objects from a constructor (from the
equivalent of class software as in C++) or from a prototype (as in
Self). JavaScript combines both. It also lets you create an object ex
nihilo (from nothing).
There are two direct ways to create a JavaScript object from nothing.
You can use the Object constructor or an object literal.
JavaScript Inheritance and Object Programming 21
As the name suggests, this creates an object. The initial capital letter
tells you that the Object() method was intended for use after the
new operator as a constructor. When you create an object this way
you can assign properties, as Listing 2-3 shows:
Listing 2-3
my_object.size = 'large';
my_object.color = 'blue';
Object Literals
Listing 2-4 shows another way the above ex nihilo object could be
created.
Listing 2-4
my_object = {
size: 'large',
color: 'blue'
};
From now on, however, we will reserve the adjective ex nihilo for
objects that are neither functions nor arrays.
Custom Objects
To create your own objects, ones that will have their own prototypes
(the next section), you write your own constructor functions, just as
you do in class-based languages.
JavaScript Inheritance and Object Programming 23
In JavaScript you can begin in much the same way that OOP
programmers begin, by writing a constructor function.
Constructors
By convention, the name of a constructor begins with a capital letter.
The constructor function assigns properties, commonly data
properties, and adds initial values. Listing 2-5 shows a simple
example.
Listing 2-5
function Dog(name, breed) {
var new_dog = this; // the 'new' object
new_dog.name = name;
new_dog.breed = breed;
}
If you chose the parameter names carefully, chances are those same
names are also good names for the object's properties. (Study the
example to convince yourself that this does not lead to ambiguities.)
The pattern in Listing 2-5, where the value of the parameter name
becomes the value of the name property, is very common.
find it. Then it looks to the prototype, where it finds the value it
seeks. If the property value is the same for all family members, the
property can be made a property of the constructor (shown in Listing
2-8), saving the wasted lookup.
Listing 2-8
Dog.diet = 'carnivore'; // not Dog.prototype
alert(Dog.diet); // same for Lassie, Snoopy...
Object Prototypes
When JavaScript sees an object property name, such as color in
object.color it looks to the object for a property of that name. If
the name does not exist it looks to the object's prototype for a
property of that name. (The prototype is another object.)
Assume that you created singers, as Listing 2-9 shows.
Listing 2-9
function Singer() {}; // no properties
var patty = new Singer(),
maxene = new Singer(),
laverne = new Singer();
Listing 2-10
patty.sing = function () {
alert('...boogie woogie bugle boy...');
}
patty.sing(); //...boogie woogie bugle boy...
Patty can sing, but her sisters cannot. We should have put this
method in the prototype, as in Listing 2-11.
Listing 2-11
Singer.prototype.sing = function () {
alert('...blows eight-to-the-bar...');
};
maxene.sing(); // she sings!
laverne.sing(); // she sings, too!
What happens if JavaScript does not find the name in the prototype?
The prototype is another object. Simply read the paragraph again.
JavaScript will look in the prototype's prototype. In JavaScript, all
objects you create are either created from the Object constructor,
and therefore Object.prototype is their prototype, or their
constructor's prototype is an object created from Object, or their
constructor's constructor is an object created from Object, and so
on.
Searching prototypes stops at Object.prototype. This is called
the prototype chain. Ultimately, Object.prototype is the
prototype of every object you create, directly or indirectly.
Bear in mind the following two important facts as you consider the
prototype chain. First, there are large families of objects (not ones
that you create) that may not have prototypes. JavaScript does not
know how to do input or output. It depends on a host environment
for all I/O. Most commonly, JavaScript runs in a browser that
provides the host environment through objects. These are called
host objects and unless the browser's authors were meticulous
(most weren't) the host objects do not have prototypes. Host objects
seldom have prototype chains.
Second, you can see how the prototype chain could be used to
implement inheritance. If you could connect your Extend family
objects so that properties not found in Extend.prototype would
be sought in Base.prototype, you would have inheritance. What
does not follow is that this would be a good way to achieve
inheritance. There are other ways that are preferable.
Many authors suggest you use the prototype chain to achieve
prototypal inheritance. In a language such as Self, creating one
object from a prototype object is referred to as inheritance. In
JavaScript, creating objects ex nihilo involves no inheritance.
Creating objects via a call to a constructor is analogous to creating
objects in class-based OOP. (JavaScript's ex nihilo objects inherit
from Object.prototype, so they aren't really ex nihilo.)
28 2 JavaScript Objects
Coding a Class
Ready to start writing code? In this chapter and the next four we
have guided programming tutorials. The road map is this:
Create a useful Box class (here in chapter 2).
Add a styles configuration object using object
programming (3).
Create a Borders class and combine it with Box objects
using composition (4).
Create a Button class that inherits from Box (5).
Add a Maskable capability and an implements() method
that adds this capability to a Box (6).
C) Add Parameters
Now we need to think about the actual work for our class. That
means deciding on the parameters for our constructor. Think
carefully here, but don't get stuck. (Think like a backpacker. When
in doubt, leave it out.)
Our sample includes a
parent (document.body or another Box)
id (unique, for the DOM element and for our own use)
pos_size (left,top, width,height array)
color (background)
E) Add Styles
Next chapter we'll do a little object programming, using a styles
configuration object. For now, we just add styles to the mainline. We
use textAlign, fontSize and padding. Go ahead and add any
that you like. (We'll do a Borders class in Chapter 4, so you might
skip border styles for now.)
OP Defined
The OOP model combines object instances, sets of name/value pairs,
with class software. The class software provides a routine to create
33
34 3 Object Programming
Dot Notation
In the familiar object.property notation, a period separates the
object reference from the property name. The latter is a constant in
source code.
var x = object.prop_name;
JavaScript Inheritance and Object Programming 35
Subscript Notation
Subscript notation allows the use of variable property names. First,
with a constant, the above example is repeated here.
var x = object['prop_name'];
Listing 3-2 shows both notations being used to create a new property
within an object. Constant and variable property names are shown.
Listing 3-2
Object.new_prop = value;
Object['new_prop'] = value;
var e = func_returning_string(args);
object[e] = value;
The pair of features above provides surprising power and grace when
programming.
The += operator does not apply to objects, but we can write a sum
function to do the same job. We want the styles in the incoming
bstyles object to add new properties to the all_styles object. If
properties of the same name already exist in all_styles, we want
to replace their values. As Listing 3-4 shows, this is more trouble to
explain than to code.
Listing 3-4
sum = function (old_object, new_object) {
var ret = {};
return ret;
} // end: sum()
This function creates a new, empty object. Then the first for/in loop
copies the old object's property names and values into the new
object. The second for/in loop copies the new property names and
values into the new object. In the process it will create new
properties, if required, or override existing properties where there is
a name conflict.
If your project wants a sum() function where the values in the old
object are preserved (not overridden by values in the new object) it is
JavaScript Inheritance and Object Programming 37
DOM related
The library functions are divided into a DOM related group, for
dealing with the browser's host environment, and a Utility group,
for everything else. Almost 80% of both make use of some form of
object programming. Listing 3-6 shows the function that deletes a
single DOM element. This would be simpler if one browser's bugs
did not make it necessary to assign null to the deleted reference.
38 3 Object Programming
Listing 3-6
delete_delem = function (delem) {
while (delem.firstChild) {
delete_delem(delem.firstChild);
}
delem.parentNode.removeChild(delem);
delem = null; // Some MSIE needs this.
} // end: delete_delem()
Listing 3-7
/** Add an event listener. */
listen_for = function (
wobj, event_name, func) {
var delem = wobj.delem;
if (delem.addEventListener !==undefined) {
delem.addEventListener(
event_name, func, false); }
else if (delem.attachEvent !==undefined) {
delem.attachEvent(
'on' + event_name, func); }
// IE before 9
else { delem['on' + event_name] = func; }
// old school!
} // end: listen_for()
Listing 3-8 shows the method in Wobj.prototype that lets us use our
preferred style.
Listing 3-8
Wobj.prototype.listen_for = function (
event_name, listen_func) {
listen_for(this, event_name,
listen_func);
}
put this back into the Fortran-style parameter list, explicitly. That
gives us object-style method calling for our Fortran-style library
functions.
Our third, and final, example from the DOM-related library functions
removes an event listener that had been added by the old-fashioned
method:
element.onclick = click_func;
Utility
We have been big fans of object programming for a long time so it
came as no surprise that most of our DOM-related utilities
manipulated object's properties. After all, the DOM is an object tree.
What we were surprised to find was how many of our utility (non-
DOM) functions also used OP. We'll start with a simple example.
Whenever we write a constructor, we also write a toString()
method. It seems you always want to have a readable version of an
object as you are developing. But what about your ex nihilo objects?
The default toString() (from Object.prototype) reports that
you have [object Object] (an object created by the Object
constructor). This is almost never helpful. Listing 3-10 shows a
simple utility that creates a readable version of an object that is
frequently helpful.
JavaScript Inheritance and Object Programming 41
Listing 3-10
o2s = function (obj) {
var ret = [];
for (var pname in obj) {
var prop = obj[pname];
if (typeof prop !== 'function') {
ret.push(pname + ': ' + prop);
}
}
return 'object{' + ret.join(',') + '}';
}
This loops through the properties by their names (in pname) and, if
they are not functions, pushes them onto an array of property
name/value pairs, as strings. That array is used as the center of the
returned string.
Listing 3-11 shows an example of object programming applied to
arrays. (Arrays are objects, in JavaScript.) It removes an element
from an array, shortening the array by one (ensuring that there are no
undefined elements created).
Listing 3-11
remove_element = function(arr, element) {
ret = [];
for (var i in arr) {
if (i !== index) { ret.push( arr[i]; )
return ret;
} // end: remove_element()
return ret;
} // end: shallow_copy()
The code that copies arrays and non-array objects is identical except
that the return value is initialized differently. The calling code does
not care. Note that using a for/in loop to copy the array correctly
handles sparse arrays and arrays that have been modified via
splice() calls.
For those new to shallow and deep copying, a shallow copy means
that values that are references to other objects are copied. A deep
copy would duplicate the objects and arrays referenced. During a
shallow copy, statements such as the following are executed:
copy.prop_name = original.prop_name;
This creates a second property with the same name and value as the
first, but it is totally separate. After the assignment, there is no
connection between the two. It's as if we had lassie.breed =
'Collie' and snoopy.breed = 'Beagle'.
If the code subsequently assigns to the copy, it does not impact the
original.
JavaScript Inheritance and Object Programming 43
copy.prop_name = some_other_object;
A) Object to String
We'll use an o2s() function (object to string) constantly as we
develop. It's job is to take an object, any object, and list its
properties. We want the name and value of each property. (You'll
want a smarter o2s() if you need to show function objects, as their
valuesthe function source codetend to be very long.)
The for (name in object) loop iterates through any object,
returning each property's name. Try using it to write an o2s()
function. Test it with object literals:
alert( o2s({breed:'Beagle', name:'Snoopy'}) );
Don't fuss overly much with the beauty of the output. It's only for use
during development. And it's only for use with objects that don't have
a nice toString() method, which can do a much better job.
44 3 Object Programming
B) A get_ps_styles() Function
Next, we'll want to put together our Box's styles in the init()
method, adding styles objects as we go along. Right now,
however, the body of Box.init() is rather crowded with the dull
work of turning a pos_size array into CSS style specifications.
We've moved this into an inner function whose job is to take the
pos_size array and return the CSS we need. (A value of 100 for
pos_size[0]-leftbecomes left: '100px'.)
Take a peek at ours, if you like, and then write your own. Test it with
an alert() or console.log() inside the Box.init() method.
You can look in the code (3, C) if you haven't a clue where to start.
(And you can look back a few pages in this chapter, for a second
opinion.) You'll find that sum() is hard-working, but that doesn't
mean it's hard to code.
Note that the sum operation is not commutative. sum(a, b) is not
equal to the sum(b, a) if a and b have like-named properties. In
the third example, above, the value of foo will be 23 after the sum,
as properties of the second object override like-named properties of
the first object. This becomes important in styles objects as we
want styles we explicitly define to override default styles.
JavaScript Inheritance and Object Programming 45
G) An alert() to Test
Finally, if you alert() or console.log() your boxes, you'll see
toString()s showing readable styles objects.
Defined Terms
Often the most controversial portion of an analysis is the
definitions. We have attempted to use terms that have (more or
less) common definitions and avoid terms that are ambiguous
(e.g., polymorphism). Wikipedia is particularly valuable in
having a community editing process that often achieves
consensus on definitions. We also check other sources, however.
Our defined terms and their references include:
Object-oriented programming Oop-W, Oop-1-5
Prototype-based programming Prtp-W, Prtp-1-5
Classes Clss-W, Clss-1-6
Instances (objects) Inst-W, Inst-1-4
Methods Mthd-W, Mthd-1-4
Inheritance Inhr-W, Inhr-1-6
Composition Cmp-W, Cmp-1-4
(A second dash, as in Oop-1-5, denotes the full range: Oop-1,
Oop-2, , Oop-5.)