Creating JavaScript Classes, Part 2: Property Inheritance (with screencast)

View Screencast | Download code

The JavaScript programming language does support extending classes through the use of constructors and prototypes. As you’ll see in the next series of posts, it is more complicated to implement than using a simple “extends” keyword or similar construct like other programming languages. This is especially true if we want to use method overrides. In this post I’m going to focus on making properties in a base class available in descendant classes, and I’ll focus on doing the same with methods in subsequent posts. For this example, I’m going to expand the original Person example from the previous post. I’m going to create a class hierarchy that looks like this:

Figure 1 - Class Diagram

Figure 1 - Class Diagram

The first JavaScript class, Person, will need to have properties for the person’s first and last names, and a method to get the person’s full name by concatenating the first and last names. These requirements are handled in the test case for the Person class. (This is not a thorough test, since all I’m really testing is the inheritance model and not that properties and functions handle all the various types of inputs.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var Assert = YAHOO.util.Assert;
 
var testCaseInheritance = new YAHOO.tool.TestCase({ 
 
  name: "Test Inheritance", 
 
  testPerson: function() {
    var jane = new Person('Jane', 'Doe');
 
    Assert.isNotNull(jane, 'A');
    Assert.areSame('Jane', jane.firstName, 'B');
    Assert.areSame('Doe', jane.lastName, 'C');
    Assert.areSame('Jane Doe', jane.getFullName(), 'D');
  }
 
});

Each of these classes will be represented in its own JavaScript file using a constructor function and function prototypes. Here is the Person.js file that contains the Person constructor:

1
2
3
4
5
6
7
8
9
10
11
/**
 * @class Person
 */
function Person(first, last) {
  this.firstName = first;
  this.lastName = last;
};
 
Person.prototype.getFullName = function() {
  return this.firstName + ' ' + this.lastName;
};

This is a simple constructor, and it passes the test. Now, I want to create a new class, Employee, that inherits from Person. This class will need to add a property for the company that the person works for. It will also have a method that takes the company name and returns it as a web address. (Of course, we wouldn’t do this in real life. This is just for illustrative purposes!)

So the first thing I am going to do is create my test to verify that these new requirements work correctly. So, I add to testCaseInheritance in the tests.js file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
testEmployee: function() {
  var jane = new Employee('Jane', 'Doe', 'CoolCo');
 
  Assert.isNotNull(jane, 'A');
 
  // Testing Employee
  Assert.areSame('CoolCo', jane.company, 'E');
  Assert.areSame('http://www.CoolCo.com', jane.getWebSite(), 'F');
 
  // Testing inherited from Person
  Assert.areSame('Jane', jane.firstName, 'B');
  Assert.areSame('Doe', jane.lastName, 'C');
  Assert.areSame('Jane Doe', jane.getFullName(), 'D');
}

After running this test to verify it fails, I then I create my new Employee constructor.

1
2
3
4
5
6
7
8
9
10
11
/**
 * @class Employee
 * @inherits Person
 */
function Employee(first, last, company) {
  this.company = company;
};
 
Employee.prototype.getCompanyWebsite = function() {
  return 'http://www.' + this.company + '.com';
};

At this point, there is no code to implement inheritance, so my tests still fail. Let’s look at the properties first. How can I get the Employee constructor to inherit the properties of the Person constructor? If I think back to how JavaScript handles objects when executing constructor functions, I might just get an idea for how to do that. If you recall, when we execute a constructor using the new keyword, JavaScript creates a new, empty object, assigns it to the this variable in the constructor function, then executes the constructor function. In the Employee constructor, I will have a this variable pointing to a new, empty object. I should be able to pass that object to the Person constructor function, and have it initialized with all the properties of the Person class.

The question is, how can I do that? I need to pass the object to the Person constructor, but I don’t want to add a new argument to the constructor function. Fortunately, JavaScript has two handy methods: apply and call. Learn these well, as you will find them useful on many occasions working with JavaScript objects.

These functions are actually methods of JavaScript functions. That is, if you have a function such as showMessage(), then this function will have the methods showMessage.apply() and showMessage.call(). Remember, functions in JavaScript are objects, so they can have properties and methods!

Both of these functions take, as their first argument, an object that you want your function to be executed against. More specifically, apply and call will execute the function (showMessage in this example) and set the this variable to the object that was passed in as the first argument. Here’s an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// A message class with a msg property
function Message(msg) {
  this.msg = msg;
}
 
// A function to show a message, but this function does not
// have a msg property and it is not part of the Message class.
function showMessage() {
  alert('You say: ' + this.msg);
}
 
// Create a Message object.  The msg property is set to "Hello".
var m = new Message('Hello');
 
// Call the showMessage function, but set the "this" variable to 
// object "m" (passed in as first argument).
showMessage.call(m);
 
// Alerts: "You say: Hello"

Study this example a bit, and make sure you understand how the call function works. The apply function works the same way. The difference between the two is the other arguments that they take, which I’ll explain as we get back to our Person and Employee classes.

So, I should be able to edit my Employee constructor so that it calls the Person constructor, and sets the this variable in the Person constructor to the empty Employee object. This will initialize the Employee object with the properties for the Person class.

1
2
3
4
function Employee(first, last, company) {
  Person.apply(this);    // "this" is our new, empty object.
  this.company = company;
};

Line 2 does the magic. Remember, Person is not a class. It is a constructor function. Therefore, it has the call and apply methods. Now if I run my test… it still fails.

An examination of the error shows that the firstName and lastName properties are not being initialized properly. Since I have called the Person constructor, the Employee object now has firstName and lastName properties, but the values of the first and last arguments are not being passed to the Person constructor. I could set those properties in my Employee constructor, where those arguments are being passed in. However, this makes calling the Person constructor pointless, since I initializing the properties will create them if they don’t already exist. In other words, I don’t need the Person constructor to create the properties. But what I really want is for the Person constructor to create and initialize the properties itself. This way, I can create multiple classes that inherit from the Person class without having to explicitly initialize the properties in each descendant class. Otherwise, I would be defeating the purpose of inheritance!

Fortunately, the call and apply methods allow me to also pass arguments to the function that I am executing. And this is the difference between the two: the call function takes a variable number of arguments (after the first argument), and each of these is passed in to the function we are executing. The apply function takes a single second argument that is an array containing the arguments to be passed in to the function we are executing.

So, I could do the following:

1
2
3
4
function Employee(first, last, company) {
  Person.apply(this, arguments);
  this.company = company;
};

Each JavaScript function has an arguments variable that is an array containing all of the arguments that have been passed in to the function. (Actually, arguments is array-like. That is, it is not really a JavaScript array. However, for our purposes in this example, we can treat it like an array.) So in this example, arguments will contain three elements corresponding to the three arguments passed into the Employee constructor: first, last and company. While this works, it does have a couple drawbacks. First, the Person constructor does not need the value for company. Second, if we add a third constructor argument to the Person constructor, say a middle name, it will be set to the value for company unless we explicitly change the Employee constructor. Third, the order of the arguments in Person and Employee must always match, which again could cause problems if we ever want to change either one.

So, a better approach would be to use the call function, like so:

1
2
3
4
function Employee(first, last, company) {
  Person.call(this, first, last);
  this.company = company;
};

This will allow us to pass in only the specific arguments we need in the specific order we need them to be in. Simply put, it gives us more control. Now if I run my test… it still fails. The properties now pass OK, but the method getFullName fails because it has not be inherited by the Employee constructor from the Person constructor.

Before I look into inheriting the methods, however, I should make sure that constructors can be chained together. That is, I should test a descendant of Employee to make sure that it still inherits properties successfully from the Person constructor and from the Employee constructor. I am going to add two new tests for this, one for the Manager class and one for the Worker class.

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
testManager: function() {
  var jane = new Manager('Jane', 'Doe', 'CoolCo');
 
  Assert.isNotNull(jane, 'A');
 
  // Testing Manager
  Assert.isArray(jane.workers, 'G');
 
  // Testing inherited from Employee
  Assert.areSame('CoolCo', jane.company, 'E');
  Assert.areSame('http://www.CoolCo.com', jane.getWebSite(), 'F');
 
  // Testing inherited from Person
  Assert.areSame('Jane', jane.firstName, 'B');
  Assert.areSame('Doe', jane.lastName, 'C');
  Assert.areSame('Jane Doe', jane.getFullName(), 'D');
},
 
testWorker: function() {
  var jane = new Worker('Jane', 'Doe', 'CoolCo');
 
  Assert.isNotNull(jane, 'A');
 
  // Testing Manager
  Assert.isNull(jane.manager, 'G');
 
  // Testing inherited Employee
  Assert.areSame('CoolCo', jane.company, 'E');
  Assert.areSame('http://www.CoolCo.com', jane.getWebSite(), 'F');
 
  // testing inherited Person
  Assert.areSame('Jane', jane.firstName, 'B');
  Assert.areSame('Doe', jane.lastName, 'C');
  Assert.areSame('Jane Doe', jane.getFullName(), 'D');
}

Note the order of the assertions in this test. It is important to remember that if a single assertion fails, that particular test ends. So, if I tried to assert on the getFullName method before the asserting on the other properties like workers, manager and company, then the test would never get to those assertions.

Testing these to ensure they fail, I then create the constructor functions to implement each of these classes:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * @class Manager
 * @inherits Employee
 */
function Manager(first, last, company) {
  Employee.call(this, first, last, company);
  this.workers = [];
};
 
Manager.prototype.hire = function(worker) {
  this.workers.push(worker);
  worker.manager = this;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * @class Worker
 * @inherits Employee
 */
function Worker(first, last, company) {
  Employee.call(this, first, last, company);
  this.manager = null;
};
 
Worker.prototype.getManagerName = function() {
  if (this.manager)
    return this.manager.getFullName();
  else
    return '';
};

Note the execution of Employee.call() in each of these constructors. When I run my test all the properties pass, but each test fails on the getFullName method and the getWebSite method, which is exactly what I expected since inheritance is not working for these yet. So, this means that the Manager constructor calls the Employee constructor, which in turn calls the Person constructor. And it all works well.

If you recall, methods are added to constructor functions through the prototype object of the function. In my next post, I’m going to see how I can inherit the prototype object, and the methods assigned to it, from one constructor to another.

Tags:

Comments (2)

Creating JavaScript Classes, Part 1: Constructors (with screencast)

View Screencast | Download code

JavaScript does not support classes. At least, not in the traditional sense. It does support basic class features, such as inheritance and method overrides. However, it does all of this though functions and function prototypes, making the implementation of class features is a bit more complicated.

JavaScript works well with object instances. There are basically two ways to create an object in JavaScript. First, you can do it directly, which creates an empty object. And second, you can use a constructor function.

Let’s look at creating an empty object directly. Creating the empty object can be done one of two ways (the latter being preferred):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// The old way...
var jane = new Object();
 
jane.firstName = 'Jane';
jane.lastName = 'Doe';
jane.getFullName = function() {
  return this.firstName + ' ' + this.lastName;
}
 
// This way is preferred...
var joe = {};
 
joe.firstName = 'Joe';
joe.lastName = 'Blow';
joe.getFullName = function() {
  return this.firstName + ' ' + this.lastName;
}

This creates two empty objects, jane and joe. Then it adds the properties firstName and lastName, and the method getFullName to both of these objects. Unlike traditional classes, where you can’t add properties and methods to an instance of the class, JavaScript objects are mutable, meaning we can change them after they’ve been created.

The drawback to this method is that if we want to create a third object with the same properties and methods as first two, we have to duplicate the code to add these properties and methods to the third object after its been created. One way around this is to create a function that we can run each new object through that will add those properties and methods, like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function initPersonObject(obj, first, last) {
  obj.firstName = first;
  obj.lastName = last;
 
  obj.getFullName = function() {
    return this.firstName + ' ' + this.lastName;
  }
}
 
var jane = { };
initPersonObject(jane, 'Jane', 'Doe');
 
var joe = { };
initPersonObject(joe, 'Joe', 'Blow');

The code above might seem a bit confusing. Look at the getFullName function, and note that it uses the variable this. What does this refer to? From the code it might not be immediately obvious, but remember that we are adding the getFullName method to the obj that was passed in. So when we actually execute the getFullName function, this will refer to the object that getFullName belongs to.

There are, of course, other variations on this theme. We could create the empty object inside the initPersonObject function, then return it from the function. We could then create our object in one line of code. This would be similar to a factory design pattern. I’ll leave it up to you to experiment with that if you’d like.

The second way to create an object instance is through the use of a constructor function, which streamlines the above code and makes it more readable. A constructor function is not a class, though it is often confused for a class. The constructor function is how we can create objects of the same type:

1
2
3
4
5
6
7
8
9
10
11
function constructPerson(first, last) {
  this.firstName = first;
  this.lastName = last;
 
  this.getFullName = function() {
    return this.firstName + ' ' + this.lastName;
  }
}
 
var jane = new constructPerson('Jane', 'Doe');
var joe = new constructPerson('Joe', 'Blow');

This doesn’t look much different that out initPersonObject from before, except that we are not passing in the obj to the constructor function, and we are always using this to refer to the object instance. The constructor function, in combination with the new keyword, allows us to create objects and initialize them at the same time.

Here’s how it works. When JavaScript encounters the new keyword, it creates a new empty object, just like what we did in the examples above. Next, it executes the constructor function and sets the this variable of that function to point to the new object. The constructor function then adds properties and methods to the new object using the this variable. When the constructor function ends, we are left with an object that has a complete set of properties and methods, just like what we had at the end of our initPersonObject example. Finally, the new keyword takes the newly constructed object and returns it. In this example, the new object is assigned to a variable.

With this method we have something similar to a class. We can now create different objects of the same type. One drawback to using this type of constructor function is that the methods we add are attached the object instance. In other words, each time we create an object instance, we are creating a new instance of the method getFullName. The function is duplicated for each object. This is silly, because the code is the same for each object. When the function is executed it should simply point to the specific object instance that it is running against. This is how traditional classes work.

JavaScript does provide a solution for this. Each constructor has a prototype property. The prototype property is an object that contains methods to be shared between object instances. When a new object instance is created, pointers to the prototype methods are created. When a prototype method is executed, the this variable in that method is set to the object instance on which the method is called. The result is that the same code is executed against a different object.

1
2
3
4
5
6
7
8
9
10
11
function constructPerson(first, last) {
  this.firstName = first;
  this.lastName = last;
}
 
constructPerson.prototype.getFullName = function() {
  return this.firstName + ' ' + this.lastName;
}
 
var jane = new constructPerson('Jane', 'Doe');
var joe = new constructPerson('Joe', 'Blow');

In this example, calling jane.getFullName() and joe.getFullName() both execute the same shared function, but in the former the this variable will point to jane, and in the latter the this variable will point to joe. In both cases, when the getFullName method is called, JavaScript first checks the object instance to see if the method exists (the method would exist in the object instance if it was added inside the constructor or after the object was created, like in our very earlier code examples). If the method does not exist in the object, JavaScript then checks the prototype of the constructor function that was used to create the object. Since the method is found there, the this variable is set to the specific object instance and the method is executed.

It’s important to understand this process. A constructor function is not a class. It is simply a function that gets executed against an object, and its prototype is referenced from that object. Notice that in all these examples I named the function “constructPerson”. I did that deliberately. One reason people get confused is that they see code where the constructor function is named like a class.

1
2
3
4
5
6
7
8
9
10
function Person(first, last) {
  this.firstName = first;
  this.lastName = last;
}
 
Person.prototype.getFullName = function() {
  return this.firstName + ' ' + this.lastName;
}
 
var jane = new Person('Jane', 'Doe');

Notice that the constructor function is now called “Person”, which implies that this is a class. It’s not. It’s a constructor function. If you use the typeof operator on the Person constructor, you will find that it returns “function”, not “class”. If you use the typeof operator on an object instance created with the Person constructor, it will return “object”, not “Person”. There is an instanceof operator in JavaScript that we can use to check if an object is an instance created with a particular constructor, and we’ll take a look at that in more detail in the next post about inheritance. But there is never any reference to a “class” anywhere in JavaScript (though that may change in a future implementation of the language. Someday. Maybe.)

At the start of this post, I mentioned that JavaScript supports inheritance and method overrides. We’ll take a look at inheritance next, and we’ll see that its going to take some additional code to get JavaScript inheritance to work like traditional class inheritance.

Tags:

Comments (4)

Test-driven development (with screencast)

View ScreencastDownload code

Before I begin posting code for this library, I just wanted to say a few words about how I develop software. I generally follow a test-driven development (TDD) methodology when writing code. For those not familiar with TDD, it is an automated unit testing method where you write a single test that describes a feature you are attempting to implement. You then write code and run your test to verify that the feature has been implemented successfully. As development progresses, you continually add tests for each feature that you want to implement. Each time you retest your code, you are also regression testing previously implemented features. And at the end of it all, assuming you have written good tests, you should have a very well unit-tested code base.

As a single developer, it is vitally important for me to be able to test code quickly and repeatedly without having to spend a lot of time manually testing or reviewing test outputs. Regression testing to make sure new code hasn’t broken old code, can take a particularly long time to test. Automated test-driven development results in a single pass or fail result, and points to the exact feature that failed. You can go back to your code months later, add a new feature, and fully test the whole code base again. TDD is thorough and efficient.

I use YUI Test for automated test-driven development. Perhaps I’ll create my own testing suite at some point (as part of this new library), but that’s not a wheel I want to re-invent right now. Watch the screencast to see a basic overview of how I use the YUI Test library to unit-test my code.

Comments (1)

Welcome, here’s what its all about

Welcome.  My name is Jason Kerchner.  I’ve been developing software for nearly twenty years, with much of my focus lately on web development.  Most recently, I’ve been getting more and more involved in using JavaScript to create rich internet applications.  As these web-based applications have become more complex, I began looking into many of the JavaScript libraries that are out there.  And to be sure, there are quite a number of them.

Nevertheless, I have decide to code an entire JavaScript library online, through this blog.  This means you will see my code in all its ugliness as development progresses.  All the mistakes, all the in-line comments, all the theories and logic behind what I am doing.  Not just code snippets, not just clean releases, but the code that I am actively working on.  Most of the code will be my own, but some might be adapted from others who have made their libraries public.  Maybe I can bring some of the best implementations together in a single code base.  And where there is no good implementation (in my opinion) maybe I can create something better.

Do we really need another JavaScript library?  Probably not.  Most developers seem happy with what’s out there, and I’ve certainly had success using existing libraries.  Do I think it will be fun?  Yup.  Do I think it will be educational, for me and others?  Yup.  Those are the reason I’m doing this, and doing it all online.  My hope is to get a decent following, and hear the opinions and suggestions of other developers. Hopefully we can all learn some useful programming techniques together.

And yes, the library will be released under an open source license.

So what kind of library will I be building, exactly?  Well, I see two basic types of JavaScript libraries out there right now.  The first basically uses an existing HTML page and manipulates it.  These are libraries like jQuery and Prototype.  The other kind takes a (mostly) empty page and uses JavaScript to build the HTML, something like ExtJS and YUI.  There is, of course, overlap between these libraries, I’m just talking about the primary manner in which they are typically used.  The library I’m going to build will be more like the latter type.

Most of these libraries, I think, focus on rich GUI controls and fancy animations.  My focus, at least initially, will be on creating a good foundation with all the necessary plumbing to make the library work.  My intent is to create code that is minimal, efficient, and easy to work with.  The last things to be implemented will be the fancy GUI controls and DOM element animations.

So, stay tuned.  The first installments will be coming soon.

Leave a Comment