Defining Return Objects in Javascript


… or, Prefer this scope to closure scope, Prefer stub scope to this scope

JavaScript is a very flexible language like Perl, and so gives you many ways to carry out the same task. Take something simple like writing a function that returns an object. How many ways can you think of to do that?

If you’ve heard of the Module Pattern, you might think that this is a well-settled question. But the Module Pattern gives you lots of leeway in implementation. In this post I’ll take away most of that wriggle room.

I recently took a look at Dojo 1.9’s code and unsurprisingly found that singleton objects were returned in five different ways. This made me wonder whether there ought to be a preferred way to return objects in JavaScript. In this post, I’ll go through four of the five 1. These four object definition styles I’ll call Factory Definition, Closure Definition, Stub Modification Definition, and Inline Definition.

Factory Definition

In the following example, instead of constructing the return object ourselves, we return the result of a factory method. Since this is just delegating the actual implementation of defining a return object to the factory method, we’ll ignore this approach going forward.

function billCalculator(){
  return calculatorFactoryMethod(.05); // taxRate = .05
}

Closure Definition

This approach, more commonly known as the Revealing Module Pattern, first defines all the components of the return object in the closure and then selects the components to be made public in the return object.

function closureBillCalculator(){
  var _taxRate = .05;
  var _calculateTax = function(subtotal){
    return subtotal * _taxRate;
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  }
  var _calculateTotal = function(subtotal){
    return subtotal + _calculateTax(subtotal) +
      _calculateTip(subtotal;
  };
  return {
    taxRate : _taxRate,
    calculateTax: _calculateTax,
    calculateTotal: _calculateTotal
    // _calculateTip stays in closure because we
    // want to keep it private
  };
}

In the above code, a taxRate scalar and three methods are defined in the closure, making them private by default. At the end, a decision is made to expose to the public only the _taxRate value and two methods — _calculateTax() and _calculateTotal(). By the way, there’s no real reason for making _calculateTip() private — I just wanted a private method in the examples.

This approach of creating an object follows the general principle of keeping object members private by default, familiar from OO languages such as Java. The major advantage of this approach is that the decision of which methods to be made public can be made independently at the end of the method, independent of the method’s implementation. Many JavaScripters also prefer this approach as a way to shorten references and avoid this scope.2

Stub Modification Definition

The most popular approach that I’ve seen is to define an empty stub object and then to modify the object’s properties before returning.

// standard Stub Modification Definition
function stubBillCalculator(){
  // An empty return stub is created.
  var stub = {};
  // The stub is progressively modified before being returned
  stub.taxRate = .05;
  stub.calculateTax = function(subtotal){
    return subtotal * stub.taxRate;
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  };
  stub.calculateTotal = function(subtotal){
    return subtotal
      + stub.calculateTax(subtotal)
      + _calculateTip(subtotal;
  }
  return stub;
}

I’m not saying this as a put-down, but I suspect the reason for the popularity of this approach is that it’s the path of least resistance when the code base grows organically. Visually, the Stub Modification Definition code just does not seem as organized as the Closure Definition code.

Inline Definition

In this style, an object literal is returned in the function’s last statement, and the components of the returned object are specified in the object literal itself. As a result, there is a clear line between private and public — public components are defined in the object literal while private components are defined in the closure.

// Inline definition
function inlineBillCalculator(){
  // This stays in the closure because we want to keep it private
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  }
  return {
    taxRate: .05,
    calculateTax: function(subtotal){
      return subtotal * this.taxRate;
    },
    calculateTotal: function(subtotal){
      return subtotal + this.calculateTax(subtotal)
        + _calculateTip(subtotal);
    }
   };
}

With the Inline Definition, one has to be careful how references are made to other variables and helper methods, as there is exactly one way to write the references in order to make the final code run — methods and variables exist only in this scope or closure scope, not both. Contrast this with the following code which shows how both Closure Definition and Stub Modification Definition allow a choice of references.

// alternate Closure Definition
function altClosureBillCalculator(){
  var _taxRate = .05;
  var _calculateTax = function(subtotal){
    // Reference to closure's _taxRate
    // replaced by reference to this.taxRate
    return subtotal * this.taxRate
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  };
  var _calculateTotal = function(subtotal){
    // Reference to closure's _calculateTax
    // replaced by reference to this.calculateTax
    return subtotal + this.calculateTax(subtotal) + _calculateTip(subtotal);
  };
  return {
    taxRate : _taxRate,
    calculateTax: _calculateTax,
    calculateTotal: _calculateTotal
  };
}
// standard Stub Modification Definition
function stubBillCalculator(){
  // An empty return stub is created.
  var stub= {};
  // The stub is progressively modified before being returned
  stub.taxRate = .05;
  stub.calculateTax = function(subtotal){
    return subtotal * this.taxRate;
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  };
  stub.calculateTotal = function(subtotal){
    return subtotal
      + this.calculateTax(subtotal)
      + _calculateTip(subtotal;
  }
  return stub;
}

What is the real substantive difference between the Closure Definition, the Stub Modification Definition, and the Inline Definition, if any? All three methods are functionally equivalent in the main objective — to return an object with a taxRate variable and two calculateXXX() methods.

Differences in Override Behavior

The first real difference between these three approaches lies in how the returned object behaves when its parts are overridden. First, let’s note that in the returned XXXBillCalculator() object, there is apparent cooperative behavior between its public members — calculateTax() depends on taxRate, and calculateTotal() depends on calculateTax().

However, if you override the taxRate, the behavior isn’t always what you expect, as demonstrated below:

var cbc = closureBillCalculator();
console.log(cbc.taxRate, cbc.calculateTax(100.0)) // .05, 5.0
cbc.taxRate = .07
console.log(cbc.taxRate, cbc.calculateTax(100.0)) // .07, 5.0

For the closureBillCalculator, we see that changing the taxRate value didn’t change the behavior of the calculateTax() method at all!

Let’s take a look at the other two approaches we’ve mentioned.

var sbc = stubBillCalculator();
console.log(sbc.taxRate, sbc.calculateTax(100.0), sbc.calculateTotal(100.0)) // .05, 5.0, 123.0
cbc.taxRate = .07
console.log(sbc.taxRate, sbc.calculateTax(100.0), sbc.calculateTotal(100.0)) // .07, 7.0, 125,0

var ibc = inlineBillCalculator();
console.log(ibc.taxRate, ibc.calculateTax(100.0), sbc.calculateTotal(100.0)) // .05, 5.0, 123.0
cbc.taxRate = .07
console.log(ibc.taxRate, ibc.calculateTax(100.0), sbc.calculateTotal(100.0)) // .07, 7.0, 125.0

For the stubBillCalculator and inlineBillCalculator implementations, changing the taxRate value did indeed change the behavior of the calculateTax() method, as we would expect. Note that the output of calculateTotal() has also been affected by the change in taxRate. That the Closure Definition, a.k.a. the Revealing Module Pattern, fails this expectation is a serious flaw.

Some readers might object with the argument that if I really intended for changes in taxRate to affect calculateTax, then I ought to have provided a setter for taxRate which could reach into the closure and modify the value. However, that argument misses the point, because in the above example, instead of changing taxRate directly, I could have chosen to override the method calculateTax(). In that case, there is no confounding issue of the lack of a getter and setter for a private variable. and yet, once again, the behavior of calculateTotal() would change for the stub- and inline- versions but not the closureBillCalculator. The point is:

If an object presents a number of cooperating member methods and variables, and you override a member, should you expect the cooperating methods to be aware of your override and react accordingly?

I think the answer is an unequivocal yes, and I’m going to make up a name for this expectation.

Ripple Principle: An override of a public member should ripple changes downstream to its dependent methods, both public and non-public.

Prefer This Scope to Closure Scope

Now is a good time to ask what was the difference in implementation between the Closure Definition and the other two responsible for the difference in override behavior? With the Closure Definition, references to dependencies used the direct reference to the closure-scoped objects _taxRate and _calculateTax(), neither of which can be accessed by the user of the returned object. When the returned object was modified, the closure-scoped objects were unaffected. With the Stub Definition, references were indirect via stub.taxRate and stub.calculateTax() using the returned object stub as proxy. With the Inline Definition, references were also indirect via this.taxRate and this.calculateTax(), using this as proxy, where this also points to the returned object. The proxied reference is what allows the latter two approaches to pick up overrides in the returned object made by the user of the object.

Thus, if we rewrite the Closure Definition using proxied this references, we can get a version which obeys the Ripple Principle. I’ll just repeat below the variation that had been mentioned before.

// alternate Closure Definition
function altClosureBillCalculator(){
  var _taxRate = .05;
  var _calculateTax = function(subtotal){
    // Reference to closure's _taxRate
    // replaced by reference to this.taxRate
    return subtotal * this.taxRate;
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  }
  var _calculateTotal = function(subtotal){
    // Reference to closure's _calculateTax
    // replaced by reference to this.calculateTax
    return subtotal + this.calculateTax(subtotal) 
      + _calculateTip(subtotal;
  };
  return {
    taxRate : _taxRate,
    calculateTax: _calculateTax,
    calculateTotal: _calculateTotal
  };
}
var acbc = altClosureBillCalculator();
console.log(acbc.taxRate, acbc.calculateTax(100.0)) // .05, 5.0
acbc .taxRate = .07
console.log(acbc.taxRate, acbc.calculateTax(100.0)) // .07, 7.0

So the problem was not intrinsic with the Closure Definition approach itself — it was in the way that functions of the Closure Definition referenced their dependencies. Unfortunately, if you google for Revealing Module Pattern, almost all the examples of the Revealing Module Pattern will use direct references rather than a proxied reference. It follows that we should

Prefer this scope to closure scope

in order to ensure that the returned object obeys the Ripple Principle. I feel, however, that I should make this statement stronger by saying that, in my opinion, you should never make direct references to objects in closure scope which will eventually be exposed as public (except for the stub, of course).

Differences in Callback Behavior

In my original conception of this blog post, I had planned to end it at the previous paragraph. However, I asked myself the question: Is there any advantage to proxying the reference by this versus proxying by stub? The answer surprised me.

Let’s look at two versions of the Stub Definition approach, one using this references and the other using stub. I’m going to add an extra method abolishTaxes() with no arguments so I can use it as a callback.

// original Stub Modification Definition
function stubBillCalculator(){
  // An empty return stub is created.
  var stub= {};
  // The stub is progressively modified before being returned
  stub.taxRate = .05;
  stub.calculateTax = function(subtotal){
    return subtotal * stub.taxRate;
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  };
  stub.abolishTaxes = function(){
    stub.taxRate = 0.0;
  };
  stub.calculateTotal = function(subtotal){
    return subtotal
      + stub.calculateTax(subtotal)
      + _calculateTip(subtotal;
  }
  return stub;
}
// alternate Stub Modification Definition
function altStubBillCalculator(){
  // An empty return stub is created.
  var stub= {};
  // The stub is progressively modified before being returned
  stub.taxRate = .05;
  stub.calculateTax = function(subtotal){
    // Reference to stub.taxRate
    // replaced by reference to this.taxRate
    return subtotal * this.taxRate;
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  };
  stub.abolishTaxes = function(){
    this.taxRate = 0.0;
  };
  stub.calculateTotal = function(subtotal){
    return subtotal
      // Reference to stub.calculateTax
      // replaced by reference to this.calculateTax
      + this.calculateTax(subtotal)
      + _calculateTip(subtotal;
  }
  return calc;
}

var sbc = stubBillCalculator();
console.log(sbc.taxRate, sbc.calculateTax(100.0)) // .05, 5.0
sbc.taxRate = .07
console.log(sbc.taxRate, sbc.calculateTax(100.0)) // .07, 7.0
var asbc = altStubBillCalculator();
console.log(asbc.taxRate, asbc.calculateTax(100.0)) // .05, 5.0
asbc .taxRate = .07
console.log(asbc.taxRate, asbc.calculateTax(100.0)) // .07, 7.0

We see that both variations obey the Ripple Principle and propagate changes downstream to affected methods.

However, the following shows how the two implementations differ when it comes to callbacks:

console.log(sbc.taxRate, asbc.taxRate, window.taxRate); // .07, .07, undefined

setTimeout(sbc.abolishTaxes, 0); // OK
setTimeout(asbc.abolishTaxes, 0); // No error, but ...

setTImeout(function(){
	console.log(sbc.taxRate, asbc.taxRate, window.taxRate); // 0.0, .07, 0.0
},0);

For implementations which use the stub proxy reference, the return object’s functions become detachable because of the complete elimination of the use of this scope (assuming the function calls another function that depends on this scope). Detachable functions can be used as callbacks or passed around as arguments without the need to first wrap them with an additional function declaration or to use .bind() helpers such as function.bind(), jQuery.bind(), or dojo.hitch(). A consistent use of stub proxy references can virtually eliminate the usage of .bind helpers in a code base. While the stub isn’t technically a scope, I’m going to summarize this piece of advice as

Prefer stub scope to this scope

Detachable Implementation Archetypes

In summary, here are the detachable, rippling versions of the Closure Definition, Stub Definition, and Inline Definition approaches.

// Detachable Closure Definition
function stubbedClosureBillCalculator(){
  var stub;
  var _calculateTax = function(subtotal){
    return subtotal * stub.taxRate;
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  }
  var _calculateTotal = function(subtotal){
    return subtotal + stub.calculateTax(subtotal) 
      + _calculateTip(subtotal;
  };
  return stub = {
    taxRate : .05,
    calculateTax: _calculateTax,
    calculateTotal: _calculateTotal
  };
}

function stubBillCalculator(){
  var stub= {};
  // The stub is progressively modified before being returned
  stub.taxRate = .05;
  stub.calculateTax = function(subtotal){
    return subtotal * stub.taxRate;
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  };
  stub.abolishTaxes = function(){
    stub.taxRate = 0.0;
  };
  stub.calculateTotal = function(subtotal){
    return subtotal
      + stub.calculateTax(subtotal)
      + _calculateTip(subtotal;
  }
  return stub;
}

function stubbedInlineBillCalculator(){
  var stub;
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  }
  return stub = {
    taxRate: .05,
    calculateTax: function(subtotal){
      return subtotal * stub.taxRate;
    },
    calculateTotal: function(subtotal){
      return subtotal + stub.calculateTax(subtotal)
        + _calculateTip(subtotal);
    }
  };
}

It turns out that the style of defining the returned object doesn’t matter — what matters is paying attention to how the dependencies are referenced. Having said that, my personal preference is the Stubbed Inline Definition because of the clear line between public and private.

Constructors and Stub Scope

Up until now, we had been talking about regular functions which return objects, not about constructor functions. It’s time to apply this new understanding of proxied references to constructors as well.

function BillCalculator(){
  this.taxRate = .05;
  this.calculateTax = function(subtotal){
    return subtotal * this.taxRate;
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  };
  this.abolishTaxes = function(){
    this.taxRate = 0.0;
  };
  this.calculateTotal = function(subtotal){
    return subtotal
      + this.calculateTax(subtotal)
      + _calculateTip(subtotal;
  }
}

var bc = new BillCalculator();
console.log(bc.taxRate, bc.calculateTax(100.0)) // .05, 5.0
bc.taxRate = .07
console.log(bc.taxRate, bc.calculateTax(100.0)) // .07, 7.0

setTimeout(bc.abolishTaxes, 0);
setTImeout(function(){
	console.log(bc.taxRate, window.taxRate); // .07, 0.0
},0);

The above shows a typical constructor implementation. Due to the use of this scope, the above implementation responds correctly to overrides but its methods are not detachable. We can make its methods detachable by converting to proxied references.

function BillCalculator2(){
  var self = this; 
  this.taxRate = .05;
  this.calculateTax = function(subtotal){
    return subtotal * self.taxRate;
  };
  var _calculateTip = function(subtotal){
    return subtotal * .18;
  };
  this.abolishTaxes = function(){
    self.taxRate = 0.0;
  };
  this.calculateTotal = function(subtotal){
    return subtotal
      + self.calculateTax(subtotal)
      + _calculateTip(subtotal;
  }
}

var bc2 = new BillCalculator2();
console.log(bc2.taxRate, bc2.calculateTax(100.0)) // .05, 5.0
bc2.taxRate = .07
console.log(bc2.taxRate, bc2.calculateTax(100.0)) // .07, 7.0

setTimeout(bc2.abolishTaxes, 0);
setTImeout(function(){
	console.log(bc2.taxRate, window.taxRate); // .07, undefined
},0);

“Self” was used as the name for the stub because it’s more natural in the context of a constructor function. By using the self reference instead of this, all the methods were made detachable. Note that only the uses of this inside the function definitions needed to be replaced.

Summary

In conclusion, for constructor functions and methods returning objects3:

* Prefer this scope to closure scope in order for overrides to affect dependent methods
* Prefer stub scope to this scope to make methods detachable as callbacks


Footnotes

1 The fifth way uses module exports.

2 This turns out to be a completely specious reason, in the larger picture.

3 What about mixins and prototype objects? That’s a topic for a future post.

3 thoughts on “Defining Return Objects in Javascript

  1. A Better setTImeout – ilinkuo

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s