Thoughts from the office by Ed Ball
Tuesday, April 19, 2005

This is hopefully the first of a series of posts about object-oriented programming in JavaScript. You can’t get far in JavaScript without learning about functions and the built-in object types, but the mechanisms for defining your own object types aren’t quite as obvious. Let’s start as simple as we can – we’ll create an object that represents a two-dimensional point:

var pt = {};
pt.X = 3;
pt.Y = 4;

No surprises there. The pt object has two properties, X and Y. We can write functions that manipulate points; for example:

function MovePoint(pt, dx, dy)
{
  pt.X += dx;
  pt.Y += dy;
}
MovePoint(pt, 1, 2);

Of course, we’d rather have a Move method on the pt object itself.

pt.Move = function (dx, dy) { this.X += dx; this.Y += dy; };
pt.Move(1, 2);

When a function is assigned to a property of an object, and that function is called using the syntax shown, the special this variable references that object, so that when pt.Move is called, this.X refers to the X property of pt.

Now, it would be rather inconvenient to type all of that every time we need a new point, so we can write a function that creates a point.

function CreatePoint(x, y)
{
  return { X : x, Y : y, Move : Point_Move };
}
function Point_Move(dx, dy)
{
  this.X += dx;
  this.Y += dy;
}
var pt = CreatePoint(3, 4);
pt.Move(1, 2);

I’ve also taken the liberty of creating a Point_Move function so that a new anonymous function isn’t created every time a new point is created. (The actual name of the Point_Move function isn’t relevant; I could have called it Krebf, but the Point_Move naming convention helps me remember that I’m using it as the Move method for a Point.)

This actually works quite well, but it would be more natural if we could use the new operator, as with built-in objects. Fortunately, this is easy enough to do – we just create a function that will serve as the constructor.

function Point(x, y)
{
  this.X = x;
  this.Y = y;
  this.Move = Point_Move;
}
var pt = new Point (3, 4);
pt.Move(1, 2);

The two approaches do almost exactly the same thing; new Point creates a new object and immediately calls the Point function as if it were a member of the new object. There are subtle (and useful) differences that I’ll describe in my next post.

4/19/2005 4:44:13 PM (Pacific Daylight Time, UTC-07:00) | Comments [0] | Code | JavaScript#
Monday, April 11, 2005

Be sure to read the revised Dispose, Finalization, and Resource Management Design Guideline, if only for Herb Sutter's annotations, in which he shamelessly demonstrates the superiority of C++/CLI in its handling of these issues.

4/11/2005 8:47:21 AM (Pacific Daylight Time, UTC-07:00) | Comments [0] | Code#
Thursday, April 07, 2005

If you are as eagerly anticipating C++/CLI as I am, you will have no trouble sitting through 90 minutes of Herb Sutter at OOPSLA 2004. He does an outstanding job of explaining why we should bother with C++ when we already have such great languages as C# and Java. Be sure to stay for the questions; it seems not everyone is enthralled with C++ and .NET…

4/7/2005 9:43:58 AM (Pacific Daylight Time, UTC-07:00) | Comments [0] | Code#
Wednesday, April 06, 2005

Have you ever wanted to determine programmatically the name of the function represented by a function object? There’s no direct way to get it, but there is an indirect way. The toString method of a function object returns the function declaration, from the function keyword at the start all the way to the last closing brace. Even “native” functions support the toString method in this fashion, though the implementation is omitted. This means that a simple regular expression can be used to determine the name of any function.

function GetFunctionName(fn)
{
  var m = fn.toString().match(/^\s*function\s+([^\s\(]+)/);
  return m ? m[1] : "";
}

The regular expression simply finds the identifier after the function keyword. If it isn’t there (as can be the case with anonymous functions) GetFunctionName returns the empty string.

4/6/2005 4:22:20 PM (Pacific Daylight Time, UTC-07:00) | Comments [0] | Code | JavaScript#
Tuesday, April 05, 2005

My last post described the BindArguments function – it returns an anonymous function that, when called, calls another function with the arguments originally specified in the call to BindArguments. Put another way, BindArguments converts a function that takes n arguments into a function that takes 0 arguments. But what if we need a function that takes 1 argument?

Imagine we have a Transform function that transforms an array of numbers in place:

function Transform(array, fn)
{
  ForEach(array, function (x, n) { array[n] = fn(x); });
}

We want to use this Divide function to do the transformation.

function Divide(n1, n2)
{
  return n1 / n2;
}

If we want to invert the numbers in the array:

Transform(array, function (x) { return Divide(1, x); });

Can we write a binding function like BindArguments that allows us to avoid the explicit anonymous function? BindArguments won’t work, because it returns a function that takes 0 arguments. If the returned function is called with any arguments, those arguments are ignored. We need the returned function to accept an argument and call Divide with 1 and that argument. We’ll call it BindFirst, because it accepts a function that takes two arguments and binds the first one.

Transform(array, BindFirst(Divide, 1));

In other words,

BindFirst(fn, x)(y) === fn(x, y)

Can we write such a function? Of course!

function BindFirst(fn, arg)
{
  return function (x) { return fn.call(this, arg, x); };
}

We can do better and create a function that will bind any number of arguments before any number of additional arguments.

// BindFirst(fn, x1, x2, …, xn)(y1, y2, …, yn) === fn(x1, x2, …, xn, y1, y2, …, yn)
function BindFirst(fn)
{
  var args = [];
  for (var n = 1; n < arguments.length; n++)
    args.push(arguments[n]);
  return function ()
    {
      var myargs = [];
      for (var m = 0; m < arguments.length; m++)
        myargs.push(arguments[m]);
      return fn.apply(this, args.concat(myargs));
    };
}

Outstanding. But wait; what if we want to divide the numbers in our array by 2?

Transform(array, function (x) { return Divide(x, 2); });

What we need here is a BindSecond function.

// BindSecond(fn, x)(y) === fn(y, x)
function BindSecond(fn, arg)
{
  return function (x) { return fn.call(this, x, arg); };
}
Transform(array, BindSecond(Divide, 2));

Better yet, BindLast, whose implementation I leave as an exercise for the reader. (It is very similar to that of BindFirst.)

// BindLast(fn, x1, x2, …, xn)(y1, y2, …, yn) === fn(y1, y2, …, yn, x1, x2, …, xn)

Is it possible to write a truly generic Bind function that can be used in place of both BindFirst and BindLast and support even more complex binding scenarios? It is, and I hope to show it to you… in a future post.

4/5/2005 1:31:44 PM (Pacific Daylight Time, UTC-07:00) | Comments [1] | Code | JavaScript#
Search
Archive
Links
Categories
Administration
Blogroll