⬆️ ⬇️

Improved CoffeeScript Inheritance

CoffeeScript brought a good abstraction of classes based on prototypes to JS.

By implementing the well-known model of inheritance and complementing it with the inheritance of cashier methods,

it makes it easy to build class hierarchies without even knowing about the prototype chains.

But this model can be improved.



The above method will not be able to completely replace the existing,

because it uses the __proto__ property, which is not available in some JS implementations.

But it allows you to significantly expand the possibilities of inheritance, while working

on top of the main model.



In addition to creating a chain of prototypes of coffee constructors uses the following code

to inherit class properties:



 for key of parent child[key] = parent[key] if __hasProp_.call(parent, key) 


That is, all properties are simply copied. With such inheritance, flexibility is lost.

')

The simplest example is that when an ancestor’s method changes, the methods in the

inherited classes. Non-listed properties are also not inherited.



It would be much better if the class properties were also inherited by the chain.

prototypes. All you need is to remove coffee after class inheritance by means of coffee.

all inherited :) and set child.__proto__ = parent .



With such inheritance, all properties of the ancestor will be available for the child class.

which can also be overridden. But it is possible to implement

interesting functionality based on what properties belong

the prototype, not the object itself.



One example is a class instance variable.

UPD: All the same I will clarify that the variable belongs to a class, not to its instance.

class instance variable Available as a property of only one class.



 Object.defineProperty Parent, 'test', get: -> @_test if @hasOwnProperty '_test' set: (val) -> @_test = val Parent.test = 1 Parent.test # => 1 Child.test # => undefined Child.test = 2 Parent.test # => 1 Child.test # => 2 


This approach to inheritance underlies the coffee_classkit package.

This package also implemented methods for working with classes taken from Ruby:

include , using append_features , extend , using extend_object ,

inherited, included, extended hooks. I will not describe them in detail here:

They are identical to Ruby counterparts, only the names in the Camcorder.

Whoever is not familiar with Ruby, I hope, without any difficulty will understand everything from the source code ,

Moreover, the methods are not more than six lines.



All functionality is available using the usual class declaration syntax:

 classkit = require 'coffee_classkit' class Child extends Parent classkit.extendsWithProto @ classkit.include @, Mixin 


For convenience, the package has a class that has all these methods in its composition.

Having inherited a class from it, you can use them in a more explicit and familiar form:



 class Example extends classkit.Module @extendsWithProto() @include Mixin 


Also included in the package is an analogue of ActiveSupport::Concern :



 class Mixin extends classkit.Module @extendsWithProto().concern() @includedBlock: -> #      @instanceVariable 'test' class @ClassMethods someClassMethod: -> someInstanceMethod: -> class Base extends classkit.Module @include Mixin @someClassMethod() (new Base).someInstanceMethod() 


More simple examples can be found in tests in the repository.



Using the described approaches, it becomes possible to write a modular

object-oriented code without breaking into the global namespace.

An extensive example can be viewed in the draft outline ,

written using CoffeeClasskit.

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



All Articles