JavaScript for the Rubyist

January 25th 2011

Background

Some time ago I took a new position at a different company. At the time of the move, I was fully expecting to give up ruby almost completely. Not because my love for the language faltered in any way, it was just that the company was predominantly Python at the time, and I was hired mainly for front-end work. I was committed to making my world javascript.

I’m writing this because the world of javascript did not welcome me with the same open arms that ruby did years ago. And, to be honest, I found that a little frustrating. This post will, hopefully, make things a little easier on the next rubyist to follow my path.

Disclaimer: I very, very much love javascript, and have since the beginning. However, due to the nature of this topic, I anticipate that my tone might be perceived as negative towards the language, code, or libraries. I absolutely do not mean this to be the case. I recognize that when I originally set down this path, I did not know what I do now, and was probably not looking in the right places. Additionally, I don’t have a time-machine to look over past me’s shoulder, so I can only recount how I felt at the time.

Disclaimer tl;dr: this is not a commentary on the javascript language or community.

First Issues

One issue I had with the javascript was that, to my eyes, I didn’t see a similar level of structure/organization (read: nesting and indentation) in the code I was reading.

For example:

// Don't read too much into this, 
  // it's just an illustration of flavor/look/feel

  var SomethingAwesome = {
    someMethod: function () {
      var someStuff = 42;
      return operation(someStuff);
    },
    anotherMethod: function (withArgument) {
      var temp = this.method(withArgument).replace(/whatever/, 'something');
    }
  }

  SomethingAwesome.prototype.protoMethodOne = function () {
    var awesomeVariable = 'some string';
    // stuff and things...

    return something;
  };

  SomethingAwesome.prototype.protoMethodTwo = function (argument) {
    var intermediate = operation(argument),
        anotherAwesomeVariable = this.protoMethodOne(intermediate);
    // stuff and things...

    return somethingElse;
  };

  var SomethingAwesome.ns = {
    isAnObjLiteral: true,
    withMethods: function () {
      return 'totally';
    }
  };

  SomethingAwesome.ns.addSomeMore = function (moreArgs) {
    // more things and stuff...

  };
  

My ruby accustomed brain had a hard time immediately locking onto the structure of code that looked like this. However, the above code would roughly translate to ruby like:

# Don't read too much into this, 
  # it's just an illustration of flavor/look/feel

  module SomethingAwesome

    def some_method

      some_stuff = 42
      operation(some_stuff)
    end

    def another_method(with_argument)
      temp = method(with_argument).gsub(/whatever/, "something")
    end

    def proto_method_one
      awesome_variable = "some string"
      # stuff and things...
      something
    end

    def proto_method_two(argument)
      intermediate = operation(argument)
      another_awesome_variable = proto_method_one(intermediate)
      # stuff and things...
      something_else
    end

    module NS

      def is_an_object_literal
        true
      end

      def with methods
        "totally"

      end

      def add_some_more(more_args)
        # more things and stuff...
      end

    end

  end

  # sidenote: translating nonsense js into coherent ruby was not as simple as I thought..
  

That’s a good enough try I think, an exact or idiomatic translation would miss the point: coming from ruby I expected a nested structure to denote relationships.

Start in the Middle

Let’s go from ruby to javascript showing how to code using a familiar ruby style:

class SomeClass

    attr_accessor :one, :two, :three

    def initialize(opts)
      @one = opts[:one]
      @two = opts[:two]
      @three = opts[:three]
    end

    def useful_method
      @four = @one + @three
    end

    def another_method(with_arg)
      @n = @two + with_arg
    end

  end

  

and now the js:

function SomeClass (opts) {

    // assigning "this" to "self" allows us to reference the 
    // class/object later when "this" may have changed
    var self = this; 

    // we don't need to pass in "opts", 

    // the function has access to it in outer scope
    function initialize () { 
      // these will now be accessible as SomeClass.one/two/three from outside,
      // or self.one/two/three from inside
      self.one = opts.one;
      self.two = opts.two;
      self.three = opts.three;
    }

    self.useful_method = function () {
      self.four = self.one + self.three;
      // remember to explicitly return in javascript

      return self.four;
    }

    self.another_method = function (with_arg) {
      self.n = self.n || 0;  // I wish javascript had ||=
      self.n += with_arg;
      return self.n;
    }

    // we have to explicitly call initialize method

    initialize();

    // and also explicitly return the object
    return self;  
  }
  

As long as you remember to explicitly return values and call the initialize method, this style can be a very clean, effective way of writing javascript. Some additional notes:

When using SomeClass in javascript be aware of the “new” operator. If you want to use the class in the most natural way, analogous to an instance of a class in ruby, you would want to use it like so:

// remember to use "new"

  var some_class = new SomeClass({
    one: 1,
    two: 2,
    three: 3

  });

  some_class.useful_method();

  some_class.another_method(5);
  

One “gotcha” is that if you don’t (or forget to) use “new”, SomeClass will behave as if all of its methods are class methods and all of its instance variables are class variables. Changing one assignment of SomeClass will change all others:

// not using "new"...
  var some_class_a = SomeClass({
    one: 1,
    two: 2,
    three: 3

  });

  some_class_a.one === 1  // true

  // not using "new"...
  var some_class_b = SomeClass({
    one: 3,
    two: 4,
    three: 5

  });

  some_class_a.one === 1 // false -- it's now 3
  

Inheritance

Ok, now what if you want to create a class that inherits from another? In ruby, this is trivial:

class SecondClass < SomeClass

    def new_public_method
      # code for the new public method...
    end

  private

    def new_private_method

      # cod for the new private method...
    end

  end
  

In javascript, using the pattern above, this is also easy. One can do it by cleverly changing the statement “self = this” in the new class to “self = new OldClass()”. This is called “Parasitic Inheritance”:

function SecondClass (opts) {
    var self = new SomeClass(opts);

    self.new_public_method = function () {
      // code for the new public method...

    }

    function new_private_method () {
      // code for the new private method...
    }

    return self;  
  }