How JavaScript Transcends OO Languages like Java and C#

In case you haven't heard, JavaScript is actually being recognized as a powerful language these days, as it possesses powerful Lisp-like qualities. Two features, closures and lambda functions (anonymous functions) are a few key elements behind this power.

To demonstrate this power, I'm going to create some JavaScript code that allows a programmer to easily create JavaScript classes at runtime. I mean classes, not objects. For example, wouldn't it be nice to have a function like this...

function person(first, last, age) {
this.first = first;
this.last = last;
this.age = age;
}
var Bob = new person("Bob", "Jones", 23);

...converted into something more concise like the example below?

var person = make_class("first,last,age");
var Bob = new person("Bob", "Jones", 23);

When you look at this make_class code, I want you to understand that make_class does not create objects, but actual class constructor functions.

JavaScript allows you to create functions on the fly WITHOUT using the dreaded eval function. I won't go into it, but eval is hazzard prone and should be avoided unless there is absolutely no other option. In our case, we don't need it as we can use a subtle, yet powerful feature called closures. Let me explain closures with a simple example.

Closures - Static Variables on Meth, and then some...

Let's say you wanted to create a function which increments a hidden internal number everytime the function is called. Let's say you expect you'll need a lot of counters each with their own values. Here's how to do it in JavaScript:

//  This function will create our counters.
function make_counter() {
var internal_counter = 0; // We will store our internal counter here
return counter; // We're returning the FUNCTION below, not a value.

function counter() { return ++internal_counter; }
}

Notice how the inner "counter" function uses the local "internal_counter" variable from make_counter. Closures allow inner function to retain variables from its parent function, or even the dreaded global scope. Look at the example of make_counter below to see how it's used. Better yet, try it.

var c1 = make_counter();  // We make our first counter.
var c2 = make_counter(); // We make our second counter.

c1() // Increments and returns 1
c1() // Increments and returns 2
c2() // Increments and returns 1
c2() // Increments and returns 2

Note that c2 has its own internal counter. This is because c2 is actually different function than c1. You can test it by typing in:

c1 == c2
// yields false

As it turns out, whenever you create a function inside another function, you're actually creating an instance of a new function object. Think about that, if you call the outer function 1000 times, 1000 new inner functions will be created. So beware of WHEN AND HOW you're using inner functions.

Let's Create Some Dynamic Classes

Back to our make_class function. Using our new knowledge of inner functions and how closures allow inner functions to retain parameters from outer functions, let's try to make a function that creates JavaScript classes. That's classes, not objects.

function make_class(field_names) {
// Turn the comma seperated list into an array
var field_names = field_names.split(",");
return constructor; // Return the constructor function defined below.

function constructor() {
// Enumerate all the arguments given to the constructor
for(var i = 0;i < arguments.length && i < field_names.length;i++) {
// Copy each argument its designated field name
this[field_names[i]] = arguments[i];
}
}
}

Let's look at this function. The first two lines are simple.

  • We convert the string into an array
  • Then return the class's constructor function below.
Now if we look at the constructor function itself, all it's really doing is reading the arguments from JavaScript argument array and linking, finding the field_names with the same index, and populating the object's properties.

With this as a starting point, it shouldn't take a lot of imagination to see how JavaScript's inherantly dynamic programming model can make creating complex object models a cinch.  Think about it.  This is a simple function that's capable of creating a very simple class in a few lines of code.  Consider a more complex example that allows you to generate classes from a slightly more complicated specification.  Think about it.

with(appmaker){
stringTypes("Name,Phone") // Use default string length
complexType("Address", "Street,City,State,Zip").apply("Address,ShipAddress,BillAddress")
table("Customer").fields("Name,Address,Phone").has("Orders,Invoices")
table("Orders").fields("ShipAddress,BillAddress")
}