I have three coffeescript classes, set up like this:
class A
class C extends A
class B
so that the prototype chain looks like this:
A -> C
B
and I need the prototype chain to look like this:
A -> B -> C
The catch being that I can't touch the definitions of A and C.
What I'd like to do is make an inject function that can be called like this:
inject B, C
that injects B into C's prototype chain before A, and then set up B's prototype chain to whatever C's was before the injection.
I thought this would be simple, something like
C extends (B extends C.prototype)
But unfortunately, things aren't quite that simple, due to all the prototype/__super__ magic that coffeescript does. Does anyone know how to inject into the prototype chain such that it's basically like you said class C extends B
and class B extends A
in the first place?
Many thanks.
Clarification: The below code DOES NOT WORK, because the properties fail to be copied over.
class A
foo: 1
class B
bar: 2
class C extends A
baz: 3
B extends A
C extends B
c = new C
console.log c.foo
console.log c.bar
console.log c.baz
[ Update: I originally answered that C extends B; B extends A
C extends B; B extends A
would work. This does indeed make C instanceof B
and B instanceof A
become true
, but it doesn't copy prototypal properties as desired. So, I've rewritten the answer.]
Let's walk 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 then run
C extends B
that overwrites C
's existing prototype with an instance of B
( child.prototype = ...
), so only C::bar
is defined.
This doesn't happen when we use the class X extends Y
syntax because properties are attached to X
's prototype only after its prototype is overwritten. So, let's write a wrapper around extends
that saves existing prototype properties, 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'd like to learn more about the inner workings of CoffeeScript classes, you might want to check out my book on CoffeeScript , published by the fine folks at PragProg. :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.