📜 ⬆️ ⬇️

Inheritance in Backbone.js

Colleagues using Backbone.js! Have you ever thought how inheritance works in this library?
Do you know how Backbone.Model.extend({}) behaves?
And you probably know and remember that extend has two optional parameters: proto props and static props.
If at least one of the above question you answered negatively - I ask for cat.
I will try to please step-by-step research, schematics, tablets and examples.

Foreword


For me personally, understanding how the used library / component works (especially the one that I use most often) is something obligatory and important. Why?

I have long been interested in the question of inheritance in Backbone.js
And so I decided, opened the source, and ... let's start!

Immediately make a reservation: inheritance works the same for all library entities, whether Model, View, Collection, or Router. In this article I will use View as an example.

Documentation


We know from the documentation that the extend method has two parameters: properties and classProperties.
Backbone.View.extend (properties, [classProperties])

You can also understand that only classProperties is optional, but in fact properties are as such.
And if the first argument is normally described for all entities, then the purpose of the second (classProperties) is hinted at only in the documentation for the Model and Collection:
If you want to make it your own business, you can extend it.

We watch source codes


Like the developer tools debbager, let's go through the extend method.
Test code:
 Backbone.View.extend({ testProp1: true }, { testProp2: true }); 

')
Stage # 1

 // Helper function to correctly set up the prototype chain, for subclasses. // Similar to `goog.inherits`, but uses a hash of prototype properties and // class properties to be extended. var extend = function(protoProps, staticProps) { var parent = this; var child; 

From the comments, we see that this is an analogue of goog.inherits (with which I have never encountered) some changes.
In the first stage, we have:


Immediately I consider it necessary to clarify two points:
1. Backbone.View Constructor is a constructor function that serves to process options, subscribe to events, call the initialize method and other actions that are very important in the work of the library and take place behind the scenes.
2. Backbone.View.prototype is a set of standard methods and properties: render, remove, etc.

Stage # 2

 if (protoProps && _.has(protoProps, 'constructor')) { child = protoProps.constructor; } else { child = function(){ return parent.apply(this, arguments); }; } 

Something interesting happens with a previously unknown child being. It is converted either to a given function in the first parameter (protoProps) constructor, or to Backbone.View Constructor. So far, we are not dwelling on this and moving on.

Stage # 3

 _.extend(child, parent, staticProps); 

Extending the child with all the properties and methods of Backbone.View Constructor and our staticProps.

In fact, the Backbone.View constructor has no properties and methods, most likely this is done just in case. Whether it is not enough, will appear sometime, and extend will not need to be rewritten.

Stage # 4

 var Surrogate = function(){ this.constructor = child; }; Surrogate.prototype = parent.prototype; child.prototype = new Surrogate; 

A certain Surrogate appears. This is the prototype of our child with you, whose constructor property is child (yes, it's the same) and prototype is Backbone.View.prototype.

Its purpose is that instead of expanding child'a with the properties and methods of Backbone.View.prototype, we simply add them as a prototype, thereby saving precious memory.

Stage # 5

 if (protoProps) _.extend(child.prototype, protoProps); child.__super__ = parent.prototype; return child; 

Add to the prototype child (Surrogate) properties and methods from protoProps (the first argument of the extend function) and create the __super__ property, which will be a link to Backbone.View.prototype.
As a result, we get a fat constructor (child), which looks like this:


Conclusion and usage examples


Using extend, we can set, besides standard properties, static. They will be available for use in the context of the constructor as well as through the constructor property .:
 var ViewConstructor = Backbone.View.extend({ protoMehod: function () { console.log(this.constructor.staticMethod()); } }, { staticProperty: 5, staticMethod: function () { return 'Hello from constructor. Property is ' + this.staticProperty; } }); var viewInstance = new ViewConstructor(); 

The context for the methods in the second argument object (staticProps) will be the ViewConstructor. For the methods in the first, viewInstance.

We can also easily use our own constructor only by setting it in the constructor property in the first parameter of the extend method:
 Backbone.View.extend({ constructor: function () { //        Backbone.View this.staticMethod(); }, render: function () { this.constructor.staticProperty; // 5 } }, { staticProperty: 5, staticMethod: function () { return 'Hello from constructor. Property is ' + this.staticProperty; } }); 

In this case, when creating an instance with the help of the operator new, the constructor redefined in the first parameter will be used, for which all static properties specified in the second parameter will be available, as well as all methods from Backbone.View.prototype.

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


All Articles