Pothibo

Memoizations, accessories & private variable in javascript

I think, I started this post over five times at least. Unless you have read this piece from a week ago, you know that I'm not a fan of huge JavaScript structure in my web application. However, it happens that I need something more robust when dealing with some part of the UX, specially, some moving parts that don't require a round trip to the server.

When this happens, I usually follow an object-oriented approach with CoffeeScript. Here I will use JavaScript.

What the hell is memoization?

The first time I read about this, I thought to myself: "Another stupid word that doesn't mean much. Sounds like legaleses." Well my thought has not changed. This is why, if I would come to talk about this with someone, this would probably be the last word I'd use. But because this post is about this exact term, I don't really have a choice to name it the way it is.

Wikipedia says:

In computing, memoization is an optimization technique used primarily to speed up computer programs by having function calls avoid repeating the calculation of results for previously processed inputs.

In a language known to any developer, it means that a function computes a value, saves it in an instance variable and return that variable value after it has processed it once.

Not that complicated.

Enter JavaScript

In JavaScript, there's no concept of function pointers, public vs private, etc. That means that if you declare a variable inside an object, there's a very good chance it's accessible from anyone. You will see that in every example below, I don't declare variable within the object's scope. I use closure to create variable inside the function. This way, the variable is not accessible from outside the function and yet is persistent throughout the object's cycle.

How do you do memoization? Here's a few example on how I do it.

Function pointer & memoization

When dealing with function that computes stuff within a class, one way I like to do it is to use closure in a way that the computation algorithm is thrown away after it's first use. Subsequent call to the same function returns the result of that computation. This way, you hide the implementation details and let a simple function on your method that returns the expected value.


function SomeClass() {

};

SomeClass.prototype.computationHeavy = function() {
  var result, fn;
  // Some computation that assign a value to 'result'
  fn = function() {
    return result;
  }

  //assign fonction to the current object
  this.computationHeavy = fn;

  return this.computationHeavy();
}

First time you call this computationHeavy, you access the whole function, do the computation and store the value into the result variable. At the end of the function, the algorithm reassigns computationHeavy to the inside function that only returns the result variable and then call that function. Because the inside function is assigned to the object and it returns the variable result, the variable lives as long as the object has that inside function assigned to it.

The variable result is not accessible outside computationHeavy function. This way, you are certain that the variable cannot be modified from the outside of the function.

Does that make sense?

Let me show you how I use this with getter & setter.

Getters & setters in the same function


log.author = function(user) {
  var value, fn;

  fn = function(user) {
    if (user === 'undefined') {
      return value;
    } else {
      value = user;
      return this;
    }
  }
  this.author = fn;

  return fn(user);
}

You can probably see a pattern now: two embedded functions, the inside functions overriding its parent so the variable stays alive.

When you call log.author the first time, it initializes the variable value and then reassign its parent to the inside function. Here again, value, is inaccessible from outside the function. When you assign a new author, like log.author(user), it does what you expect it to do: it sets the user. Also, you can return the object so your setter becomes chainable. When calling the get version log.author(), it returns the user, as expected.

Why should I do this?

On way to see this is that you force single access point to your variable. Sometimes, when you have access to a variable, you start changing the value from more than one place/condition. This can become very hard to track down and can therefore become hard to debug.

If you have an unexpected value for a setter using this method, you know for sure where that variable was set and start debugging from there.

Bonus

While writing this post, I started thinking if others were using it. So I showed this to some people I knew. @plbabin and I had a discussion about the getter/setter more specifically and we agreed that it'd be cool if there would have something like attr_accessor in Coffeescript. So he wrote a small gist about it and I made small modification to the logic along with a test suit for your pleasure. Now, you can set attr_accessor in your Coffeescript class if you extend the Accessor class provided.

It will dynamically create a getter/setter like the one shown above.


class @User extends @Accessible
  attr_accessible: ['name', 'email']

The source is available on GitHub, enjoy!

Get more ideas like this to your inbox

You will never receive spam, ever.