Inheriting 'Class' properties in Backbone - javascript

I am trying to determine how it may be possible to inherit "class" properties of Backbone objects. Class properties are explained here:
https://taurenmills.wordpress.com/2011/10/08/backbone-js-with-class-properties/
We can do inheritance with Backbone, like so:
var BaseModel = Backbone.Model.extend({
someFunc1: function(){
},
someFunc2: function(){
}
},
{ //class properties below
newInstance: function(attrs,opts_{
var model = new BaseModel(attrs);
model.randomProp = opts.randomProp;
return model;
}
});
var SubModel = BaseModel.extend({
someFunc2: function(){ //overrides someFunc2 in BaseModel
someFunc1(); calls someFunc1 in BaseModel
}
},
{ //class properties below
newInstance: function(attrs,opts){
var model = new SubModel (attrs);
model.randomProp = opts.randomProp;
return model;
}
}
);
my question is: how can we inherit the "class" functions from BaseModel?
I would like for my subclasses of BaseModel to inherit the class function newInstance.
But I don't think that's possible. Coming from Java, it's not straightforward as how to inherit static methods which refer to the subclass itself in the inherited static method, not the superclass.
ignoring what I just said, in other words, I would like to do something like:
newInstance: function(attrs,opts){
var Constr = this.constructor; //*but* the 'this' keyword will not be available in the newInstance function, which is like a static method in Java
var model = new Constr(attrs);
model.randomProp = opts.randomProp;
return model;
}
the reason I want to implement the class function is so that I can set a specific property on the new model instance everytime that function is invoked.

You can access method from your base class by using your object's prototype.
For example if you wanted to call your base classes initialize method you would do the following
//base class
initialize: function (attributes, options) {
this.someProperty = options.somePropery
},
//sub class
initialize: function (attributes, options) {
BaseModel.prototype.initialize.call(this,attributes, options);
},
That said, inheritance really works a bit differently in JavaScript (this isn't really unique to backbone) to how it works in Java and you probably should read up a bit on the object prototype.

Related

How to create instance of object from prototype method

Is it possible to create an instance of an object from it's prototype if the prototype is being used for multiple sublclasses?
For example, if I have:
var BaseClass = Backbone.Model.extend({
createNewForMap: function(map) {
// Here I would like to create a new instance of the
// class that the method is being called for.
}
});
var ClassOne = BaseClass.extend({});
var ClassTwo = BaseClass.extend({});
Then, somewhere in my application code, I want to be able to call:
var model = ClassOne.createNewForMap(map);
or
var model = ClassTwo.createNewForMap(map);
And have model be an instance of ClassOne or ClassTwo.
It is possible to define a static method on the BaseClass, that will serve as a factory function for it or any children classes, that inherit it.
Backbone.Model.extend allows you to specify so-called classProperties, that might be considered as something similair to static methods from conservative OOP programming.
var BaseClass = Backbone.Model.extend({}, {
// A static method for invoking constructor function.
createNewForMap: function(map) {
return new this;
}
});
var ClassOne = BaseClass.extend({
initialize: function() { this.foo = 'bar' }
});
var ClassTwo = BaseClass.extend({
initialize: function() { this.foo = 'buz' }
});
console.log(ClassTwo.createNewForMap().foo); // buz
<script src="//underscorejs.org/underscore-min.js"></script>
<script src="//backbonejs.org/backbone-min.js"></script>
You can use the constructor property to get a reference to an object's "class":
Object.prototype.constructor
Returns a reference to the Object function that created the instance's prototype. Note that the value of this property is a reference to the function itself, not a string containing the function's name.
So you can say things like:
createNewForMap: function(map) {
var obj = new this.constructor();
//...
}
and obj will be the same type of thing as this.
Demo: https://jsfiddle.net/ambiguous/avk4z6Le/

Understanding Prototypal Inheritance methodologies in JS

I have read every article and example on the first page of Google and I still am having a hard to completely understanding how to properly implement Prototypal Inheritance in JavaScript. The biggest challenge I'm facing is I am seeing many different ways to implement the inheritance.
First I will start with what I want to achieve if this was C#:
C#
class Base {
public string UI { get; set; } // Using a string just for simplicity
}
class Book : Base {
public Book(string title) {
this.title = title;
}
private string title { get; set; } // Title of book
}
Then I can instantiate a Book and be able to access UI on each instance:
var myBook = new Book("East of Eden");
myBook.UI = "some string"; // This work.. all Book instances have THEIR OWN UI string
JavaScript
Now lets say I have a base object in JS that I want all other objects to inherit from:
function Base() {
this.UI = {}
}
I then want another object type to inherit this model like this:
function Book(title){
this.title = title;
}
Book.prototype = new Base();
// Sometimes I have seen this line instead... nothing seems to work at all when I use this though, so I don't understand whats happening here
//Book.prototype = Object.create(Base.prototype);
Book.prototype.constructor = Book;
Book.prototype.getTitle = function(){
return this.title;
}
var myBook = new Book("East of Eden");
var anotherBook = new Book("Grapes of Wrath");
console.log(myBook.getTitle()); // East of Eden
myBook.UI.isRead = true;
console.log(myBook.UI);
console.log(anotherBook.getTitle()); // Grapes of Wrath
anotherBook.UI.isHardcopy = true;
myBook.UI.isRead = false;
console.log(anotherBook.UI); // This UI object has isRead on it as well!!! NOOOO
So this doesn't really work because both instances are sharing the same UI object, but what I want is for them to have their OWN instance of the UI object.
Another method I have seen is to not use the 'new' keyword at all and only use Object.create() to get new objects. However, I am not sure how I would implement my Base class with some subclass like Book and then create multiple instances of Book, each with their own UI properties.
Could someone please give me an example of how to inherit a base class and create instances of that subclass with their own UI objects? Thanks
EDIT
So would the "simple" way of achieve what I want just be to do something like:
var Base = {
UI: {}
}
function Book(title){
_.extend(this, Base);
this.title = title;
}
var myBook = new Book("East of Eden");
myBook.UI.prop = 5; // This works now but doesn't utilize true inheritance at all!
Prototypes are linked and not copied. This means that when you did:
function Base(){
this.UI = {}
}
Book.prototype = new Base();
Book.prototype.constructor = Book;
The prototype of your Book constructor will be a new instance of Base. All your instances of Book will have the same prototype, the same instance of Base. Since it's this object which holds the UI property, all Book instances will fallback to the same object property.
Think that your Prototype will be:
var proto = {
UI : { }
}
All your Book instances will have access to this object:
var a = new Book('East of Eden');
var b = new Book('Grapes of Wrath');
a.UI.prop = 'prop'; //proto.UI.prop === 'prop'
b.UI.prop === 'prop'; //because it's also proto.UI.prop
If you actually define a property on Book instances, say on its constructor:
function Book(title){
this.title = title;
this.UI = { };
}
You'll see that they are different objects:
a.UI !== b.UI //true
a.UI.prop = 'prop';
b.UI.prop !== b.UI; //true
Calling the constructor is the most obvious way to also initialize the properties on their children:
function Book(title){
Base.call(this);
this.title = title;
}
Regarding the difference between new Base() and Object.create(Base.prototype).
new Base() will initialize the object and call the constructor, while Object.create(Base.prototype) will do basically the same, except it won't call the constructor. This means, that the prototype won't have the properties set on the constructor (UI).
The biggest challenge I'm facing is I am seeing many different ways to implement the inheritance.
There really is only one correct way.
Use Object.create to establish inheritance:
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
configurable: true,
}
});
Then apply the parent constructor in the child constructor to the child instance:
function Child() {
Parent.call(this);
}
This is basically what happens under the hood if you'd use ES2015's new class syntax.
See Benefits of using `Object.create` for inheritance for more details on Object.create and why you want to use it in this case.

Is it possible in javascript to inherit properties from another class - rather than an existing object?

For example in PHP if you wanted a class to inherit properties of another class you would reference the parent class
<?php
class BaseController {
// ....
}
class UserController extends BaseController {
// ....
}
However in javascript if you want a new class or object to inherit some properties from another class - it seems you need to assign an - already instantiated - object of the class you want to inherit from to your objects prototype.
e.g. If you want to create a brand new object and access the properties of an existing object:
var robot = {
active : "yes",
primeDirective : function() {
console.log("Must kill all humans!");
}
};
var bender = Object.create(robot);
bender.primeDirective(); => "Must kill all humans!"
or if you have an existing object, you can assign the existing object to prototype using __proto__
var robot = {
active : "yes",
primeDirective : function() {
console.log("Do a flip!");
}
};
var bender = {
name : "Bender Bending Rodriguez"
};
bender.__proto__ = robot;
bender.primeDirective(); => "Do a flip!"
both these methods require an already created object to inherit properties from, is it possible for a class definition to inherit from another class - similar to the extends functionality in PHP?
In ES5 JavaScript the correct way to derive a class is to use Object.create passing the base class's prototype, not an instance, and then to ensure that all functions are part of that prototype.
// a properly formed constructor function
function Robot(name) {
this.name = name;
}
// all functions belong on the prototype
Robot.prototype.primeDirective = function() {
...
}
// create derived class
function BendingUnit22(name) {
Robot.call(this, name); // invoke superclass constructor
}
// create and attach a new prototype object chained from the base class
BendingUnit22.prototype = Object.create(Robot.prototype);
// and re-attach the constructor
BendingUnit22.prototype.constructor = BendingUnit22;
// add new or overriding functions here
BendingUnit22.prototype.primeDirective = function() {
...
}
var bender = new BendingUnit22("Bender Bending Rodriguez");
You'll need to create a constructor (or an ES6 class) if you want to inherit a little less dynamically.
function Robot() {
this.active = true;
}
Robot.prototype.primeDirective = function() {
console.log("Must kill all humans!");
};
var bender = new Robot(); // Yey!
To create a new inheriting constructor:
function HumanoidRobot() {
Robot.apply(this, arguments);
this.legs = 2;
}
HumanoidRobot.prototype = Object.create(Robot.prototype);
HumanoidRobot.prototype.constructor = HumanoidRobot;
This process becomes a lot easier with ES6 classes, which hide all this ugliness from you!
class Robot {
constructor() {
this.active = true;
}
primeDirective() {
console.log("Must kill all humans!");
}
}
class HumanoidRobot extends Robot() {
constructor() {
super()
this.legs = 2;
}
}
No, there is no built in mode for extending classes in Javascript, because it is not a class based but prototype based language.
However, there are many frameworks that implement the 'extend' behaviour, for example in Prototype:
var robot = Class.extend({ ... });
var bender = robot.extend({ ... });
http://ejohn.org/blog/simple-javascript-inheritance/
But many other frameworks support the same, for example Underscore _.extend()
http://underscorejs.org/#extend
There are 3 kind of inheritance possible in JavaScript.
Pseudo Classical (Like the one you are looking for)
/**
* Create a new constructor function, whose prototype is the parent object's prototype.
* Set the child's prototype to the newly created constructor function.
**/
var extendObj = function (childObj, parentObj) {
var tmpObj = function () {}
tmpObj.prototype = parentObj.prototype;
childObj.prototype = new tmpObj();
childObj.prototype.constructor = childObj;
};
(https://jsfiddle.net/nikdtu/4wzuwhqw/)
Functional
(https://jsfiddle.net/nikdtu/eh7u4pxd/)
Prototypal (Object.create)
(https://jsfiddle.net/nikdtu/dnjkx8w1/)
Luckily I documented that during a project and captured those JSfiddles.
I hope You will find the required help from these.
I think this is what you are looking for
// define the Person Class
function Person() {}
Person.prototype.walk = function(){
alert ('I am walking!');
};
Person.prototype.sayHello = function(){
alert ('hello');
};
// define the Student class
function Student() {
// Call the parent constructor
Person.call(this);
}
// inherit Person
Student.prototype = new Person();
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
// replace the sayHello method
Student.prototype.sayHello = function(){
alert('hi, I am a student');
}
// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
alert('goodBye');
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true

Reference instance of parent class in prototype extension [duplicate]

I have built a large application using JavaScript prototype and inheritance.
But I am having a hard time organizing my code.
For example I have a class carousel which has many functions like this:
Carousel.prototype.next = function () {...}
Carousel.prototype.prev = function () {..}
Carousel.prototype.bindControls = function () {..}
I would like to organize my code like this :
Carousel.prototype.controls = {
next: function () { ... } ,
prev: function() { ... },
bindControls: function () { .. }
}
But this will cause the value of "this" being lost. I can keep track of it using a global instance but this will cause problems when the class is inherited for example In another file I have something like this to override parent class
BigCarousel.prototype.next = function () {...}
My inheritance is done like this:
Function.prototype.inheritsFrom = function (parentClass) {
if (parentClass.constructor === Function) {
//Normal Inheritance
this.prototype = $.extend(this.prototype , new parentClass);
this.prototype.constructor = this;
this.prototype.parent = parentClass.prototype;
}
else {
//Pure Virtual Inheritance
this.prototype = $.extend(this.prototype, parentClass);
this.prototype.constructor = this;
this.prototype.parent = parentClass;
}
return this;
};
So I can do:
BigCarousel.inheritsFrom(Carousel)
Does anyone know how can I work around the "this" value ?
You could make Controls a class of it's own:
var Controls = function (controllable_object) {
this.ref = controllable_object;
};
Controls.prototype.next = function () {
this.ref.foo();
}
// ..
var Carousel = function () {
this.controls = new Controls(this);
};
// ..
This doesn't allow you to override the implementation of Controls though. With more dependency injection you'd get something like:
var Controls = function (controllable_object) {
this.ref = controllable_object;
};
Controls.prototype.next = function () {
this.ref.foo();
}
// ..
var Carousel = function () {
this.controllers = [];
};
Carousel.prototype.addController = function (controller) {
this.controllers.push(controller);
};
// ..
var carousel = new Carousel();
carousel.addController(new Controls(carousel));
My inheritance is done like this:
$.extend(this.prototype , new parentClass);
Ouch. This is not inheritance (with new BigCarousel instanceof Carousel), but just copying properties. Maybe this is enough for you, but then you should call it mixin. Also, you should avoid using new for inheritance.
But this will cause the value of "this" being lost. How can I work around that?
It's impossible to have this point to the parent object with nested properties (as long as you don't want to explicitly set it every time). You have only two choices:
Forget it, and organize your methods by prefixing them (controlNext, controlBind, …)
Give each of your carousels its own controls object. For inheritance, make them CarouselControls instances for example. This especially fits well if those controls are quite independent from the carousel, and don't need to access the carousel they're attached to everywhere. If they are not, you still can pass a reference to the parent carousel into their constructor for example:
this.controls = new CarouselControls(this);
Also, for customizing the controls in different carousels, you might have to subclass the CarouselControls as well - or you prepare your Controls object to serve for different carousels in general, so that from BigCarousel you can
Carousel.call(this); // make this a carousel
this.controls.activate({big: true, fast: false}); // or something
You can use the .bind method of Function.
In Javascript Functions inherit from Object, so they have their own methods. One of those methods is .bind:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
Also you are doing inheritance wrong, the right way with raw Javascript is:
ChildClass= function() {
ParentClass.apply(this, arguments); //calling parent constructor
//constructor
};
ChildClass.prototype= new ParentClass();
Then you can simply do this on your constructor:
Courossel= function() {
ParentClass.apply(this, arguments); //calling parent constructor
this.controls.next.bind(this);
this.controls.prev.bind(this);
this.controls.bindControls.bind(this);
}
But I have to say that Frits suggestion is better, make the controls their own class and instantiate it on Carousel constructor passing a reference to your Carousel instance (the this keyword). Just don't call it ".ref", it's confusing.

Inheritance of static members in MooTools

I'm using the MooTools class system, and I'd like to be able to access any static member of a particular class without having to know the full inheritance chain. For example, if I have a ChildClass that extends BaseClass, and
BaseClass.foo = function() { /*...*/ }
I'd like to be able to call ChildClass.foo().
To this end, I'm thinking of modifying the MooTools Class method as follows:
function Class(params)
// ...
// var newClass = ...
var parentClass = params.Extends;
if (parentClass) {
newClass.__proto__ = parentClass;
}
// ...
}
This will set up each class object's prototype chain to point to its parent class.
If a static member from a higher class is hidden in a more derived class, so be it.
Notwithstanding the use of the deprecated __proto__, am I on the right track here? Does anyone see any glaring problems?
You can always extend the Extend Mutator:
(function(){
var original = Class.Mutators.Extends;
Class.Mutators.Extends = function(parent) {
original.call(this, parent);
var members = {};
for (var key in parent) {
if (parent.hasOwnProperty(key) && !this.hasOwnProperty(key)) {
members[key] = parent[key];
}
}
this.extend(members);
};
}());
You should check out Mark Obcena's book.

Categories

Resources