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
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.