Internal Classes In CoffeeScript
CoffeeScript provides us with a very nice syntax for creating classes.
class Dog
constructor: (@name) ->
bark: ->
"Woof, #{@name}"
Here is the equivalent code in JavaScript:
function Dog(name) {
this.name = name;
}
Dog.prototype.bark = function() {
return "Woof, " + this.name;
};
We can use the same syntax for creating internal / private classes. (I don’t know if there’s a correct name for it, but I’m basically referring to a class which is defined within the parent class.)
class Dog
class Bark
constructor: (name) ->
@name = name
sound: ->
"Woof, #{@name}"
constructor: (name) ->
@barkHelper = new Bark(name)
bark: ->
@barkHelper.sound()
dog = new Dog("Beethoven")
dog.bark() # Woof, Beethoven
This works as you would except - we can access the internal / private class from within the parent class (Dog), but not from outside it.
bark = new Bark("Beethoven") # ReferenceError: Bark is not defined
We can also expose this internal class to outside callers - we can effectively treat the parent class as a namespace.
class Dog
class @Bark
constructor: (name) ->
@name = name
sound: ->
"Woof, #{@name}"
constructor: (name) ->
@barkHelper = new Dog.Bark(name)
bark: ->
@barkHelper.sound()
bark = new Dog.Bark("Beethoven")
bark.sound() # Woof, Beethoven
I find this especially useful for testing. For example, you may find it necessary to extract some piece of functionality into an internal class, but if we didn’t expose that internal class in this way there would be no way to test it. It might seem messy to expose an internal member purely for testing, but I think this is a safe middle ground - it is still very obvious that the internal / private class should only be used in the context of the parent class.
Here is the equivalent code in JavaScript:
var Dog = (function() {
Dog.Bark = (function() {
function Bark(name) {
this.name = name;
}
Bark.prototype.sound = function() {
return "Woof, " + this.name;
};
return Bark;
})();
function Dog(name) {
this.barkHelper = new Dog.Bark(name);
}
Dog.prototype.bark = function() {
return this.barkHelper.sound();
};
return Dog;
})();
var bar = new Dog.Bark("Beethoven");
bark.sound();
Happy coding.