Embedding a new class in the coffeescript inheritance chain

I have three coffeescript classes configured as follows:

class A class C extends A class B 

so that the prototype chain looks like this:

 A -> C B 

and I need a prototype chain to look like this:

 A -> B -> C 

The trick is that I cannot touch definitions A and C.

What I would like to do is make an injection function that can be called as follows:

 inject B, C 

which introduces B into the prototype chain C to A, and then sets the prototype chain B to what C was before the injection.

I thought it would be just something like

 C extends (B extends C.prototype) 

But, unfortunately, it's not that simple, due to all the prototypes of / __ super__ magic that coffeescript does. Does anyone know how to inject prototypes into a chain, so basically, as you said class C extends B and class B extends A in the first place?

Thank you very much.

Clarification: the code below DOES NOT WORK because the properties cannot be copied.

 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 
+4
source share
1 answer

[ 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. :)

+3
source

Source: https://habr.com/ru/post/1369177/


All Articles