My CoffeeScript Enlightenment: Class Variables

For the longest time, I have used JavaScript without any classes. I never even once thought that classes were possible in JavaScript. That is, until I discovered JavaScript’s secret feature, Ruby mode. I think some people call it CoffeeScript, but whatever, JavaScript’s Ruby mode is one of the absolute BEST abstractions that I have ever used. That’s coming from someone who has never used a language abstraction before, but enough of the small talk. Moving on, I want to share a little about classes in JavaScript’s Ruby mode and explain how it works.

In the following example here, we have a class in CoffeeScript. For most object orientated programmers, this is pretty straight forward and it shouldn’t be a surprise to anyone.

class HelloWorld
  personsName = null
  greeting = null

  setName: (name) ->
    personsName = name

  setGreeting: (greet) ->
    greeting = greet

  greet: () ->
      console.log greeting, personsName

Just to go over the class briefly:

  • We have a class named HelloWorld.
  • We have 2 class variables that are initialised to null.
  • We have 2 mutator methods, 1 for each variable.
  • We have a greet method that prints these 2 variables to screen.

Let’s instantiate it, and say hello!

JapanesePerson = new HelloWorld()
JapanesePerson.setGreeting "こにちは"
JapanesePerson.setName "あさみ"
JapanesePerson.greet()
# こにちは あさみ

As expected, the JapanesePerson greeted us in Japanese with こにちは あさみ. So far so good, grrreat!

tonythetiger

Let’s have the EnglishPerson greet us now!

EnglishPerson = new HelloWorld()
EnglishPerson.greet()

Oh whoops, I forgot to set the variables, but that’s not problem since the variables are initialised to null anyways.

YEAH FUCKING RIGHT BECAUSE RUBY MODE COMES WITH RUBY MAGIC.

If you ask the EnglishPerson to greet you here, she would actually speak Japanese and say こにちは あさみ.

So what the fuck CoffeeScript? Why you many unpredictable? Let’s take a deeper look into the compiled JavaScript and see what is actually happening.

var EnglishPerson, HelloWorld, JapanesePerson;

HelloWorld = (function() {
 var greeting, personsName;

 function HelloWorld() {}

 personsName = null;

 greeting = null;

 HelloWorld.prototype.setName = function(name) {
 return personsName = name;
 };

 HelloWorld.prototype.setGreeting = function(greet) {
 return greeting = greet;
 };

 HelloWorld.prototype.greet = function() {
 return console.log(greeting, personsName);
 };

 return HelloWorld;

})();

JapanesePerson = new HelloWorld();
JapanesePerson.setGreeting("こにちは");
JapanesePerson.setName("あさみ");
JapanesePerson.greet();

EnglishPerson = new HelloWorld();
EnglishPerson.greet();

In this JavaScript example, we have a variable with an anonymous function that is evaluated right away (self-invoking as some say), and inside that, we have a HelloWorld prototype setup and then we return the prototype.

As you see here the two variables, greeting and personsName, are outside of the object constructor. Instantiating HelloWorld is as expected, you get a new object. But the interesting part here is the two variables. The reason why the EnglishPerson was greeting in Japanese was because of closures. Closures remember the outer scope variables that it was created in, so since HelloWorld was created within the self-invoking anonymous function already, creating a new object from the returned object constructor allowed the EnglishPerson and the JapanesePerson to speak the same language.

All in all, the nuances of Ruby mode is a small price to pay for the amount of value you get if you ignore debugging the abstraction part. I did have different expectations of behaviors between the CoffeeScript code and the JavaScript code, but this shouldn’t serve as a deterrent for using Ruby mode.  Different expectations, more disappointment.

 

  • Wesley

    That’s one reason why I prefer to just use regular JavaScript instead of CoffeeScript!

    Btw, have you heard of an immediately-invoked function expression (IIFE)? That’s another name for the anonymous function that is evaluated right away. 🙂

    • Douglas Mak

      I have, lol. There are so many attempts to coin a terminology, but I just keep it simple.