In projects with a small frontend, it is not always wise to use heavy frameworks like backbone, ember or knockout. Nevertheless, the need to use models, inheritance and qualitative interaction between them remains. I bring to your attention the
Neutrino framework, which does all of the above, while its size does not exceed 100 lines of code.
Any feedback on the framework is welcome.
A simple demo with inheritance and events can be viewed
here .
Class creation
To create a class, call the
extend method of the
_neutrino.Root object. As an argument, we give it an object that contains the methods and static elements of the future class.
var Model = _n.Root.extend({
The
extend method returns a class constructor.
')
Creating Class Instances
To create an instance of a class, we simply call its constructor with the keyword
new and pass only one argument. This argument must be an object containing all the necessary data. The contents of the object will be recorded in the
data field of the newly created object.
var model = new Model({ id: 1 }); alert(model.data.id);
Default values
For any property of the data object, we can set the default value:
var Model = _n.Root.extend({ defaults: { id: "default id" } }); var model = new Model(); alert(model.data.id);
Constructors
We can set a pseudo-constructor for any class. The pseudo-constructor function is called
construct . Its behavior is completely equivalent to the usual constructor — it is called when the object is created, and can return a value that will be returned as the result of the operation of the
new operator. In the pseudo-constructor code, the parent method must be called using
this._superCall (); var Model = _n.Root.extend({ construct: function() { this._superCall(); alert("Hello world"); } });
Inheritance
Neutrino supports full inheritance:
- You can create child classes using the extend method of the base class;
- The constructor of any class contains the superclass property, which directly points to the constructor of the parent class;
- From any method, you can easily call the nearest available parent method;
- The defaults field is automatically merged with all parent data.
Let's look at a simple example:
var Parent = _n.Root.extend({ defaults: { a: 1, b: 2 }, construct: function() { this._superCall(); alert(this.getSum()); }, getSum: function() { return this.data.a + this.data.b; } }); var Child = Parent.extend({ defaults: { a: 10, c: 3 }, getSum: function() { return this.superCall() + this.data.c; } }); new Parent();
Call parent methods
From the inside of a method, there are two ways to call the nearest parent method. If you need to call the parent method with the same parameters as the current method was called, you can use
this._superCall (); ... someMethod: function(a, b, c) { return this._superCall();
If the parent method needs to be called with other parameters, you need to use a direct link to the nearest parent method -
this._superMethod; ... someMethod: function(a, b, c) { return this._superMethod(a + 1, b + 1, c + 1);
In fact,
this.superCall (); this is the abbreviated equivalent of
this._superMethod.apply (this, arguments) ;
Developments
Events are a distinct way to organize the interaction of models ... Models in Neutrino can generate events and subscribe to events of other models.
Event generation
To generate an event in a model, you need to call its
fireEvent method. It needs to pass two parameters - the name of the event is
eventName and (optionally) an
info object containing any additional information.
model.fireEvent("item-added", { item: item
Handling your own events
When a model generates an event, its own
onOwnEvent method is
called first , which receives the
eventName and
info parameters.
... onOwnEvent: function(eventName, info) { switch(eventName) { case "item-added":
Subscribe to events
To subscribe to an event of a model, you need to call its
subscribe method and pass it two parameters — a handler function and the name of the event you want to subscribe to. If you do not specify the name of the event (or pass an asterisk
* as the name of the event), your handler will be called when any event is generated, Otherwise, only at the event to which you subscribed.
Naturally, the handler will receive the
eventName and
info parameters when it is called.
function commonHandler(eventName, info) { switch(eventName) { case "e1": alert("e1 fired"); break; } } function specificHandler(eventName, info) { alert("e1 fired"); } model.subscribe(commonHandler); model.subscribe(specificHandler, "e1"); model.fireEvent("e1");
Event handling by model methods
Usually, there is a need to handle the event of one model by the method of some other model. To keep
this context and possibly some other data relevant at the time of subscription, you can, of course, use a closure:
... processItem: function(item) { var self = this; item.subscribe(function(eventName, info) { self.onItemEvent(eventName, info, item); }); }, onItemEvent: function(item, eventName, info) { ... }
However,
Neutrino provides an easier way to do this.
item.subscribe(this.onItemEvent.bind(this, item));
A bind () function is attached to each model method in Neutrino, which will call your method with the correct
this context and any additional parameters.
A simple example will help clarify understanding:
var binding = this.onItemEvent.bind(this, 1, 2)); setTimeout(function() { binding(3, 4);
Using
bind () , you first specify the desired context (usually this), then any number of additional parameters (a, b). When we call the result function of the binding with parameters (c, d), then in the end, we come to the call of our method with parameters (a, b, c, d).
Any feedback on the framework is welcome.