To reap the benefits of prototypal inheritance in JavaScript, you have to define a constructor and then attach properties to its associated prototype. CoffeeScript allows you to do both of those things at once using the class keyword:
| class MyFirstClass |
| sayHello: -> console.log "Hello, I'm a class!" |
| |
| myFirstInstance = new MyFirstClass |
| myFirstInstance.sayHello() |
| Hello, I'm a class! |
In just two lines, we’ve defined a no-op constructor named MyFirstClass and attached a method called sayHello to its prototype. Of course, we could do that in two lines without the class keyword. So let’s look at a more involved example.
It’s a well-known fact that the trouble a tribble makes is directly proportional to the number of existing tribbles. Let’s write a class that demonstrates that wisdom:
| class Tribble |
| constructor: -> |
| @isAlive = true |
| Tribble.count += 1 |
| |
| # Prototype properties |
| breed: -> new Tribble if @isAlive |
| die: -> |
| return unless @isAlive |
| Tribble.count -= 1 |
| @isAlive = false |
| |
| # Class-level properties |
| @count: 0 |
| @makeTrouble: -> console.log ('Trouble!' for i in [1..@count]).join(' ') |
There’s a lot of new syntax here, so let’s go through it one piece at a time.
Each time a new tribble is created, the constructor method runs. (This syntax reflects JavaScript semantics: for any function X, X.prototype.constructor is X.) The constructor sets the isAlive property on the new instance to true and then bumps Tribble.count up by one.
A tribble has two prototypal methods: one to spawn new tribbles and another to remove itself from the population. It’s perfectly kosher to reference the constructor (in this case, Tribble) from prototypal methods, because the constructor will always be defined before they’re called.
In the class body, @ points to the constructor rather than the prototype, and you can define “static” (class-level) properties with the special syntax @key: value (which is equivalent to @key = value). So we’re initializing Tribble.count to be 0 and defining a Tribble.makeTrouble() function. Making count a class-level property rather than a prototype-level one avoids any potential ambiguity over whether an instance’s count is specific to that instance or shared.
Let’s test this:
| tribble1 = new Tribble |
| tribble2 = new Tribble |
| Tribble.makeTrouble() # "Trouble! Trouble!" |
| Trouble! Trouble! |
By instantiating two tribbles, we’ve bolstered Tribble.count to two, so Tribble.makeTrouble’s loop for i in [1..@count] has two iterations. Let’s see if we can bring the count back down:
| tribble1.die() |
| Tribble.makeTrouble() # "Trouble!" |
| Trouble! |
Killing off tribble1 again would have no effect, thanks to the unless @isAlive check. And as we know, tribbles are born pregnant, so it won’t be long before the remaining individual repopulates the species:
| tribble2.breed().breed().breed() |
| Tribble.makeTrouble() # "Trouble! Trouble! Trouble! Trouble!" |
| Trouble! Trouble! Trouble! Trouble! |
That covers the basics of the class syntax. But much like tribbles, classes are famous for replicating themselves. So let’s close this chapter by introducing the best part of CoffeeScript classes: inheritance.
3.144.90.182