[ Update: I initially replied that C extends B; B extends A C extends B; B extends A will work. It really makes C instanceof B and B instanceof A become true , but it does not copy prototype properties as desired. So, I rewrote the answer.]
Letβs go through this:
class A foo: 1 class B bar: 2 class C extends A baz: 3
At this point, C::foo is 1, and C::baz is 3. If we run
C extends B
which overwrites the existing C prototype with an instance of B ( child.prototype = ... ), so only C::bar defined.
This does not happen if we use the syntax class X extends Y , because the properties are bound to the prototype X only after overwriting its prototype. So, write a wrapper around extends that preserves existing prototype properties and then restores them:
inherits = (child, parent) -> proto = child:: child extends parent child::[x] = proto[x] for own x of proto when x not of child:: child
Applying this to our example:
inherits B, A inherits C, B console.log new C instanceof B, new B instanceof A # true, true console.log B::foo, B::bar, B::baz # 1, 2, undefined console.log C::foo, C::bar, C::baz # 1, 2, 3
If you want to know more about the inner workings of CoffeeScript classes, you can check out my CoffeeScript book published by great people in PragProg. :)