Monday, November 3, 2014

Using objects for switch statements

I ran across a post where the author wished switch statements returned a value. The switch statement has always looked to me like a poor choice in programming. It seems like we should be able to use polymorphism instead of what is another version of a long if/else chain. However, there are cases when we could be over-designing and a switch statement would do the job.
// Not valid ECMAScript
var color = switch(x) {
  case   1: 
    'blue' ; break;
  case   2: 
    'red'  ; break;
  default : 
    'green';
};

The author, Dusan Jovanovich, proposed a cond function in the likes of lisp
cond( x, 
      1, 'blue', 
      2, 'red', 
      'green' );
Since lisp is the language where non-primitives are lists, and JavaScript is the language where non-primitives are basically maps, I would suggest a cond function that feels more like JavaScript.
function cond(val, cases, fallback, scope) {
    var theCase = cases.hasOwnProperty(val) ? cases[val] : fallback;
    return typeof theCase == "function" ? 
        theCase.call(scope || this, val) : 
        theCase; 
}
So that the previous cond call would look like:
var color = cond(x , {
   1: 'blue',
   2: 'red',
}, 'green');
One of the benefits of this function is that you can pass functions to each condition, so that we get almost all functionality of a switch:
jQuery('a').each(function(){
 switch(x) {
  case 1: 
    $(this).css({ color: 'blue'});
    $this.slideDown();
    break ;
  case 2: 
    $(this).css({ color: 'red'});
    $this.slideUp();
    break ;
  default : 
    $(this).css({ color: 'green'});
 }
});

// Could become
jQuery('a').each(function(){
  cond(x, {
    1: function() {
        $(this).css({ color:'blue'});
        $(this).slideDown();
    },
    2: function() {
        $(this).css({ color:'red'});
        $(this).slideUp();
    },
  }, function() {
        $(this).css({ color:'green'});
  }, this);
});
If you have multiple cases where the almost the same thing needs to happen (fallthroughs), the switched value is passed to each of the conditions, so you could nest them. At this point, this probably would not be a good idea, but here it goes anyway.
jQuery('a').each(function(){
  // Save 'this' instead of passing in a scope in this case
  var $this = $(this);
  
  function fallThrough12(y) {       
      cond(y, {
           1: function() {
              $this.css({ color:'blue'});
           }
           2: function() {
              $this.css({ color:'red'});
           }
      });
      $this.slideDown();
  }
  cond(x, {
    1: fallThrough12,
    2: fallThrough12,
    3: function() {
        $this.css({ color:'yellow'});
        $this.fadeOut();
    }
  }, function() {
        $this.css({ color:'green'});
  });

Monday, October 6, 2014

Understanding prototypal inheritance

Many developers coming from a classical inheritance model find it difficult to grasp JavaScript's prototypal inheritance. In this post, I will explain how inheritance is achieved in JavaScript and what pitfalls to avoid.

Consider the following code where we create an instance of "Class" using code that looks like classical inheritance
function Class() {
    this.obj2 = {c: 'c'}
}

Class.prototype = {
    primitive: 'a',
    obj: { a: 'a' },
    arr: [1,2,3]
};

var inst1 = new Class();
var inst2 = new Class();

The following diagram explains which objects are being created. Solid lines are direct links and dashed lines are chaining objects through the prototype.


An equivalent way of creating an instance, in a more prototypal, albeit more verbose fashion is the following:
// Create an empty object chaining it to Class.prototype
var inst1 = Object.create(Class.prototype);
// Initialize the object using the constructor
Class.call(inst1);

The important thing to understand is that the prototype object is shared by all instances. A common pitfall is to instantiate an object/array on the prototype without realizing that mutating that object will modify it for all instances. In our example, the {a: 'a'} object and the [1,2,3] array is shared among the instances, whereas each instance has its own copy of {c: 'c'}
// The two instances share the same instance of obj
// which may be unexpected
inst1.obj.a = 'b';
console.log(inst1.obj); // {a: 'b'}
console.log(inst2.obj); // {a: 'b'}

// same for arrays (since array is a mutable object)
inst1.arr.push(4);
console.log(inst1.arr); // [1,2,3,4]
console.log(inst2.arr); // [1,2,3,4]

// to get around this, create the child objects in constructor
// now changing obj2 in instance1 does not affect instance2
inst1.obj2.c = 'd';
console.log(inst1.obj2); // {c: 'd'}
console.log(inst2.obj2); // {c: 'c'}
Note that this problem doesn't occur when sharing primitives on the prototype. When we read a property from an object, it will first look for the property in the specified object, if it doesn't find it, it will go up the prototype chain looking for that object. However, when you write to an object, it always writes to the specified object, not the prototype. For example

// Here we creating a new property on inst1, which now shadows 
// the "primitive" property on "Class.prototype"
inst1.primitive = 'b';
// Still reading from Class.prototype
console.log(inst2.primitive); // 'a'
// Read "obj" from the prototype and then write over the "a" 
// property on that "obj" (from the prototype)
inst1.obj.c = 5;
// Create a new object that writes a new "obj" property on inst2 
// directly and shadows "obj" on the prototype
inst2.obj =  {c: 6};

Lessons to learn:

  • Initializing immutable objects on a prototype keeps a single copy, so it saves memory and initialization code
  • Don't share mutable objects on the prototype unless you want changes in one instance to reflect in all instances.
  • Initializing primitives on the prototypes is always OK, because they can't be mutated directly through instances
 If you'd like to play around with the above code, go to http://jsfiddle.net/mendesjuan/cdaq5b11/3/

Tuesday, August 17, 2010

Javascript Inheritance Done Right

I've seen a number of different ways of implementing Javascript inheritance. The real test to see if inheritance is working correctly is that the instanceof operator works correctly. So all the approaches that copy methods from the base to the subclass are out of the question because they do not correctly setup the prototype chain. Another consequence of inheritance by copying is that if you change the prototype after the object has been instantiated, the object does not magically inherit the added property.

This leads me to the most common approach which does correctly set up prototype chain but has a few problems:

function Animal(name) {
  this.name = name;
}

// This style of setting the prototype to an object
// works for classes that inherit from Object.
Animal.prototype = {
  sayMyName: function() {
    console.log(this.getWordsToSay() + " " + this.name);
  },
  getWordsToSay: function() {
    // Abstract
  }
}

function Dog(name) {
  // Call the parent's constructor
  Animal.call(this, name);
}

// Setup the prototype chain mmm... calling
// the Animal without the required params?
Dog.prototype = new Animal();

Dog.prototype.getWordsToSay = function(){
  return "Ruff Ruff";
}

var dog = new Dog("Lassie");
dog.sayMyName(); // Outputs Ruff Ruff Lassie
console.log(dog instanceof Animal); // true
console.log(dog.constructor); // Animal ???? That's not right
console.log("name" in Dog.prototype)// true, but undefined

Alright, what's going on?
  • Dog.prototype now has a property called "name" that is set to undefined.
    That wasn't intentional. I knew that call to Animal's constructor was funny. Though that won't cause a problem, because we add a "name" to the object in the constructor, it's not very elegant
  • dog (the instance) has a constructor property but it points to Animal,
    that's just wrong

How can we fix that? Here's a first try

// This is a constructor that is used to setup inheritance without
// invoking the base's constructor. It does nothing, so it doesn't
// create properties on the prototype like our previous example did
function surrogateCtor() {}

function extend(base, sub) {
  // Copy the prototype from the base to setup inheritance
  surrogateCtor.prototype = base.prototype;
  // Tricky huh?
  sub.prototype = new surrogateCtor();
  // Remember the constructor property was set wrong, let's fix it
  sub.prototype.constructor = sub;
}

// Let's try this
function Animal(name) {
  this.name = name;
}

Animal.prototype = {
  sayMyName: function() {
    console.log(this.getWordsToSay() + " " + this.name);
  },
  getWordsToSay: function() {
    // Abstract
  }
}

function Dog(name) {
  // Call the parent's constructor
  Animal.call(this, name);
}

// Setup the prototype chain the right way
extend(Animal, Dog);

Dog.prototype.getWordsToSay = function(){
  return "Ruff Ruff";
}

var dog = new Dog("Lassie");
dog.sayMyName(); // Outputs Ruff Ruff Lassie
console.log(dog instanceof Animal); // true
console.log(dog.constructor); // Dog
console.log("name" in Dog.prototype)// false

Nice isn't it? Let's add some syntactic sugar to make it more user friendly.
  • Add a reference to the base class so we don't have to hard code it
  • Pass the object's prototype methods into the call


function surrogateCtor() {}

function extend(base, sub, methods) {
  surrogateCtor.prototype = base.prototype;
  sub.prototype = new surrogateCtor();
  sub.prototype.constructor = sub;
  // Add a reference to the parent's prototype
  sub.base = base.prototype;

  // Copy the methods passed in to the prototype
  for (var name in methods) {
    sub.prototype[name] = methods[name];
  }
  // so we can define the constructor inline
  return sub;
}

// Use the same animal from above
function Dog(name) {
  // Call the parent's constructor without hard coding the parent
  Dog.base.constructor.call(this, name);
}

extend(Animal, Dog, {
  getWordsToSay: function(){
    return "Ruff Ruff";
  }
});


One more step, I don't even like hard coding the name of the class in the methods in case I rename it, how can we fix that?

The solution is to wrap everything in a self executing function and create a reference to the constructor

Dog = (function(){
  // $this refers to the constructor
  var $this = function (name) {
    // Look, no hardcoded reference to this class's name
    $this.base.constructor.call(this, name);
  };

  extend(Animal, $this, {
    getWordsToSay: function(){
      return "Ruff Ruff";
    }
  });

  return $this;
})();

With this final approach, renaming the class or changing its parent requires changing a single place (for each change).

Update

This article was written a while ago, when Object.create wasn't as well supported. The extend function could be simplified to be

function extend(base, sub, methods) {
  sub.prototype = Object.create(base.prototype);
  sub.prototype.constructor = sub;
  sub.base = base.prototype;

  // Copy the methods passed in to the prototype
  for (var name in methods) {
    sub.prototype[name] = methods[name];
  }
  // so we can define the constructor inline
  return sub;
}


Thursday, August 5, 2010

Constructors without using "new"

When creating a constructor in Javascript, one has to worry about a problem: what if someone calls your constructor without using new?

function Point(x,y) {
  this.x = x;
  this.y = y
}

// This is good
var pt = new Point(20,30);

// This is not
var pt2 = Point(20,30);

You'll notice when you don't use new, pt2 is undefined after the call. Even worse, we've added two variables to the global scope, x, y. That is because if you call a function without specifying the context, the browser passes in the global object, which is "window";

The first attempt to fix this is the following

function Point(x,y) {
  if (this instanceof Point) {
    this.x = x;
    this.y = y
  } else {
    return new Point(x,y);
  }
}

// This is good
var pt = new Point(20,30);

// This is OK also
var pt2 = Point(20,30);

However, that seems like a lot of boiler plate code to add to every constructor. How can we abstract that? Here's what I came up with.

/**
 * Wraps the passed in constructor so it works with
 * or without the new keyword
 * @param {Function} realCtor The constructor function.
 *    Note that this is going to be wrapped
 *    and should not be used directly 
 */
function ctor(realCtor){
  // This is going to be the actual constructor
  return function wrapperCtor(){
    var obj; // object that will be created
    if (this instanceof wrapperCtor) {
      // Called with new
      obj = this;
    } else {
      // Called without new. Create an empty object of the
      // correct type without running that constructor
      surrogateCtor.prototype = wrapperCtor.prototype;
      obj = new surrogateCtor();
    }
    // Call the real constructor function
    realCtor.apply(obj, arguments);
    return obj;
  }
}

/** 
 * A function that does nothing, so we can create objects 
 * of a prototype without running unnecessary code. 
 * See its usage above
 */
function surrogateCtor() {}

// Create our point contructor
Point = ctor(function(x,y){
  this.x = x;
  this.y = y;
});

// This is good
var pt = new Point(20,30);
// This is OK also
var pt2 = Point(20,30);

// It's even ok with inheritance, though a 3D point shouldn't
// really inherit from a 2D point, it's just to make a point...
Point3D = ctor(function(x,y,z){
  Point.call(this, x, y);  
  this.z = z;
});

// Note that this is not the best way to setup inheritance.
// My next post will explain a better way
Point3D.prototype = new Point();

var pt3D = new Point3D(5,3,8);

// Outputs true
console.log(pt3D instanceof Point3D && pt3D instanceof Point);

Thursday, July 29, 2010

Canvas Rounded Corner Rectangles

I've recently started using the canvas tag and  needed to draw rounded corner rectangles. I did find a good post explaing how to do it but I didn't find a nice method so I decided to create one.  I took Futomi Hatano's code  and abstracted it into a method.

/**
 * Draws a rounded rectangle using the current state of the canvas. 
 * If you omit the last three params, it will draw a rectangle 
 * outline with a 5 pixel border radius 
 * @param {CanvasRenderingContext2D} ctx
 * @param {Number} x The top left x coordinate
 * @param {Number} y The top left y coordinate 
 * @param {Number} width The width of the rectangle 
 * @param {Number} height The height of the rectangle
 * @param {Number} radius The corner radius. Defaults to 5;
 * @param {Boolean} fill Whether to fill the rectangle. Defaults to false.
 * @param {Boolean} stroke Whether to stroke the rectangle. Defaults to true.
 */
function roundRect(ctx, x, y, width, height, radius, fill, stroke) {
  if (typeof stroke == "undefined" ) {
    stroke = true;
  }
  if (typeof radius === "undefined") {
    radius = 5;
  }
  ctx.beginPath();
  ctx.moveTo(x + radius, y);
  ctx.lineTo(x + width - radius, y);
  ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
  ctx.lineTo(x + width, y + height - radius);
  ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  ctx.lineTo(x + radius, y + height);
  ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
  ctx.lineTo(x, y + radius);
  ctx.quadraticCurveTo(x, y, x + radius, y);
  ctx.closePath();
  if (stroke) {
    ctx.stroke();
  }
  if (fill) {
    ctx.fill();
  }        
}

And it can be used like the following:

// My html contains a canvas with id "rounded-rect" 500X350
var ctx = document.getElementById("rounded-rect").getContext("2d");
// Draw using default border radius, 
// stroke it but no fill (function's default values)
roundRect(ctx, 5, 5, 50, 50);
// To change the color on the rectangle, just manipulate the context
ctx.strokeStyle = "rgb(255, 0, 0)";
ctx.fillStyle = "rgba(255, 255, 0, .5)";
roundRect(ctx, 100, 5, 100, 100, 20, true);
// Manipulate it again
ctx.strokeStyle = "#2d6";
ctx.fillStyle = "#abc";
roundRect(ctx, 100, 200, 200, 100, 50, true);

Which will produce the following output:




For Firefox and Chrome (and maybe other browsers), you can do the following for syntactic sugar

CanvasRenderingContext2D.prototype.roundRect = 

function(x, y, width, height, radius, fill, stroke) {
  if (typeof stroke == "undefined" ) {
    stroke = true;
  }
  if (typeof radius === "undefined") {
    radius = 5;
  }
  this.beginPath();
  this.moveTo(x + radius, y);
  this.lineTo(x + width - radius, y);
  this.quadraticCurveTo(x + width, y, x + width, y + radius);
  this.lineTo(x + width, y + height - radius);
  this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  this.lineTo(x + radius, y + height);
  this.quadraticCurveTo(x, y + height, x, y + height - radius);
  this.lineTo(x, y + radius);
  this.quadraticCurveTo(x, y, x + radius, y);
  this.closePath();
  if (stroke) {
    this.stroke();
  }
  if (fill) {
    this.fill();
  }        
}

// Now you can just call
var ctx = document.getElementById("rounded-rect").getContext("2d");
ctx.roundRect(5, 5, 50, 50);

Here's a JsFiddle that you can edit freely