In Douglas Crockford's JavaScript: The Good Parts he recommends that we use functional inheritance. Here's an example:
var mammal = function(spec, my) {
var that = {};
my = my || {};
// Protected
my.clearThroat = function() {
return "Ahem";
};
that.getName = function() {
return spec.name;
};
that.says = function() {
return my.clearThroat() + ' ' + spec.saying || '';
};
return that;
};
var cat = function(spec, my) {
var that = {};
my = my || {};
spec.saying = spec.saying || 'meow';
that = mammal(spec, my);
that.purr = function() {
return my.clearThroat() + " purr";
};
that.getName = function() {
return that.says() + ' ' + spec.name + ' ' + that.says();
};
return that;
};
var kitty = cat({name: "Fluffy"});
The main issue I have with this is that every time I make a mammal or cat the JavaScript interpreter has to re-compile all the functions in it. That is, you don't get to share the code between instances.
My question is: how do I make this code more efficient? For example, if I was making thousands of cat objects, what is the best way to modify this pattern to take advantage of the prototype object?
Well, you just can't do it that way if you plan on making lots of mammal or cat. Instead do it the old fashioned way (prototype) and inherit by property. You can still do the constructors the way you have above but instead of that and my you use the implicit this and some variable representing the base class (in this example, this.mammal).
cat.prototype.purr = function() { return this.mammal.clearThroat() + "purr"; }
I'd use another name than my for base access and store it in this in the cat constructor. In this example I used mammal but this might not be the best if you want to have static access to the global mammal object. Another option is to name the variable base.
Let me introduce you to Classical Inheritance that never uses prototype. This is a bad coding exercise but will teach you the real Classical Inheritance which always compared to prototypal inheritance:
Make a custructor:
function Person(name, age){
this.name = name;
this.age = age;
this.sayHello = function(){return "Hello! this is " + this.name;}
}
Make another cunstructor that inherits from it:
function Student(name, age, grade){
Person.apply(this, [name, age]);
this.grade = grade
}
Very simple! Student calls(applies) Person on itself with name and age arguments takes care of grade arguments by itself.
Now lets make an instance of Student.
var pete = new Student('Pete', 7, 1);
Out pete object will now contain name, age, grade and sayHello properties. It owns all those properties. They are not uplinked to Person through prototype. If we change Person to this:
function Person(name, age){
this.name = name;
this.age = age;
this.sayHello = function(){
return "Hello! this is " + this.name + ". I am " this.age + " years old";
}
}
pete will no recieve the update. If we call pete.sayHello, ti will return Hello! this is pete. It will not get the new update.
if you want privacy and you dont like protyping you may or may-not like this approach:
(note.: it uses jQuery.extend)
var namespace = namespace || {};
// virtual base class
namespace.base = function (sub, undefined) {
var base = { instance: this };
base.hierarchy = [];
base.fn = {
// check to see if base is of a certain class (must be delegated)
is: function (constr) {
return (this.hierarchy[this.hierarchy.length - 1] === constr);
},
// check to see if base extends a certain class (must be delegated)
inherits: function (constr) {
for (var i = 0; i < this.hierarchy.length; i++) {
if (this.hierarchy[i] == constr) return true;
}
return false;
},
// extend a base (must be delegated)
extend: function (sub) {
this.hierarchy.push(sub.instance.constructor);
return $.extend(true, this, sub);
},
// delegate a function to a certain context
delegate: function (context, fn) {
return function () { return fn.apply(context, arguments); }
},
// delegate a collection of functions to a certain context
delegates: function (context, obj) {
var delegates = {};
for (var fn in obj) {
delegates[fn] = base.fn.delegate(context, obj[fn]);
}
return delegates;
}
};
base.public = {
is: base.fn.is,
inherits: base.fn.inherits
};
// extend a sub-base
base.extend = base.fn.delegate(base, base.fn.extend);
return base.extend(sub);
};
namespace.MyClass = function (params) {
var base = { instance: this };
base.vars = {
myVar: "sometext"
}
base.fn = {
init: function () {
base.vars.myVar = params.myVar;
},
alertMyVar: function() {
alert(base.vars.myVar);
}
};
base.public = {
alertMyVar: base.fn.alertMyVar
};
base = namespace.base(base);
base.fn.init();
return base.fn.delegates(base,base.public);
};
newMyClass = new namespace.MyClass({myVar: 'some text to alert'});
newMyClass.alertMyVar();
the only downside is that because of the privacy scope you can only extend the virtual classes and not the instanceable classes.
here is an example of how i extend the namespace.base, to bind/unbind/fire custom events.
// virtual base class for controls
namespace.controls.base = function (sub) {
var base = { instance: this };
base.keys = {
unknown: 0,
backspace: 8,
tab: 9,
enter: 13,
esc: 27,
arrowUp: 38,
arrowDown: 40,
f5: 116
}
base.fn = {
// bind/unbind custom events. (has to be called via delegate)
listeners: {
// bind custom event
bind: function (type, fn) {
if (fn != undefined) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' is not supported');
}
this.listeners[type].push(fn);
}
return this;
},
// unbind custom event
unbind: function (type) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' is not supported');
}
this.listeners[type] = [];
return this;
},
// fire a custom event
fire: function (type, e) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' does not exist');
}
for (var i = 0; i < this.listeners[type].length; i++) {
this.listeners[type][i](e);
}
if(e != undefined) e.stopPropagation();
}
}
};
base.public = {
bind: base.fn.listeners.bind,
unbind: base.fn.listeners.unbind
};
base = new namespace.base(base);
base.fire = base.fn.delegate(base, base.fn.listeners.fire);
return base.extend(sub);
};
To proper use Javascript-prototype based inheritance you could use fastClass https://github.com/dotnetwise/Javascript-FastClass
You have the simpler inheritWith flavor:
var Mammal = function (spec) {
this.spec = spec;
}.define({
clearThroat: function () { return "Ahem" },
getName: function () {
return this.spec.name;
},
says: function () {
return this.clearThroat() + ' ' + spec.saying || '';
}
});
var Cat = Mammal.inheritWith(function (base, baseCtor) {
return {
constructor: function(spec) {
spec = spec || {};
baseCtor.call(this, spec);
},
purr: function() {
return this.clearThroat() + " purr";
},
getName: function() {
return this.says() + ' ' + this.spec.name + this.says();
}
}
});
var kitty = new Cat({ name: "Fluffy" });
kitty.purr(); // Ahem purr
kitty.getName(); // Ahem Fluffy Ahem
And if you are very concerned about performance then you have the fastClass flavor:
var Mammal = function (spec) {
this.spec = spec;
}.define({
clearThroat: function () { return "Ahem" },
getName: function () {
return this.spec.name;
},
says: function () {
return this.clearThroat() + ' ' + spec.saying || '';
}
});
var Cat = Mammal.fastClass(function (base, baseCtor) {
return function() {
this.constructor = function(spec) {
spec = spec || {};
baseCtor.call(this, spec);
};
this.purr = function() {
return this.clearThroat() + " purr";
},
this.getName = function() {
return this.says() + ' ' + this.spec.name + this.says();
}
}
});
var kitty = new Cat({ name: "Fluffy" });
kitty.purr(); // Ahem purr
kitty.getName(); // Ahem Fluffy Ahem
Btw, your initial code doesn't make any sense but I have respected it literally.
fastClass utility:
Function.prototype.fastClass = function (creator) {
var baseClass = this, ctor = (creator || function () { this.constructor = function () { baseClass.apply(this, arguments); } })(this.prototype, this)
var derrivedProrotype = new ctor();
if (!derrivedProrotype.hasOwnProperty("constructor"))
derrivedProrotype.constructor = function () { baseClass.apply(this, arguments); }
derrivedProrotype.constructor.prototype = derrivedProrotype;
return derrivedProrotype.constructor;
};
inheritWith utility:
Function.prototype.inheritWith = function (creator, makeConstructorNotEnumerable) {
var baseCtor = this;
var creatorResult = creator.call(this, this.prototype, this) || {};
var Derrived = creatorResult.constructor ||
function defaultCtor() {
baseCtor.apply(this, arguments);
};
var derrivedPrototype;
function __() { };
__.prototype = this.prototype;
Derrived.prototype = derrivedPrototype = new __;
for (var p in creatorResult)
derrivedPrototype[p] = creatorResult[p];
if (makeConstructorNotEnumerable && canDefineNonEnumerableProperty) //this is not default as it carries over some performance overhead
Object.defineProperty(derrivedPrototype, 'constructor', {
enumerable: false,
value: Derrived
});
return Derrived;
};
define utility:
Function.prototype.define = function (prototype) {
var extendeePrototype = this.prototype;
if (prototype)
for (var p in prototype)
extendeePrototype[p] = prototype[p];
return this;
}
[* Disclaimer, I am the author of the open source package and the names of the methods themselves might be renamed in future` *]
Related
I've got two object prototypes like this:
function Tag(name, description) {
this.name = name;
this.description = description || null;
}
function Category(name, description) {
this.name = name;
this.description = description || null;
}
Both of them are exactly the same, which seems awkward. Is it possible to merge them both into an object named 'Entity', and refer to them both by different names (the original 'Tag' and 'Category')?
This may be further complicated by the fact I need to refer to the current prototype name inside the prototype.
Tag.prototype.toJSON = function() {
return {
__type: 'Tag',
name: this.name,
description: this.description
};
};
How can I apply the same 'toJSON' extension to the 'Entity' object, but make sure it returns 'Tag' or 'Category' in the '__type' field, dependent on which object is being used?
I would do something like this:
Dummy = function () {};
Entity = function (name) {
this.name = name;
};
Entity.prototype.toString = function () {
return "My name is " + this.name + ".";
};
A = function () {
Entity.call(this, 'A');
};
Dummy.prototype = Entity.prototype;
Dummy.prototype.constructor = A;
A.prototype = new Dummy();
B = function () {
Entity.call(this, 'B');
};
Dummy.prototype = Entity.prototype;
Dummy.prototype.constructor = B;
B.prototype = new Dummy();
document.body.innerHTML = ""
+ (new A()) + "<br />"
+ (new B());
Here is a small function to make things cleaner (hopefully):
function Nothing () {};
function extend (Sup, proto) {
function Class () {
if (this.init) {
this.init.apply(this, arguments);
}
}
Nothing.prototype = Sup.prototype;
Nothing.prototype.constructor = Sup;
Class.prototype = new Nothing();
delete Nothing.prototype;
for (var k in proto) {
Class.prototype[k] = proto[k];
}
return Class;
}
Here is how to use it:
Entity = extend(Nothing, {
init: function (name) {
this.name = name;
},
toString: function () {
return "My name is " + this.name + ".";
}
});
A = extend(Entity, {
init: function () {
var sup = Entity.prototype;
sup.init.call(this, 'A');
}
});
B = extend(Entity, {
init: function () {
var sup = Entity.prototype;
sup.init.call(this, 'B');
}
});
I'm working on making performance updates on my javascript code.
In Firefox I got this warning:
mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create
I wrote some scripts to prove this, and the results are great: without mutation a simple script runs 66% faster.
But I have trouble converting my code without mutation, I can't write the getters:
This is what I have now:
// Class
function FooBar(options) {
this.options = options;
}
// Prototype
FooBar.prototype = {
// Getters
get a() {
return this.options.a;
},
get b() {
return this.options.b;
},
get ab() {
return this.options.a + this.options.b;
},
// Methods
displayOptions: function() {
console.log(this.options);
}
};
// Code
var options = {
a: 'foo',
b: 'bar'
};
var fooBar = new FooBar(options);
console.log(fooBar.a);
console.log(fooBar.b);
console.log(fooBar.ab);
fooBar.displayOptions();
The getters as a prototype using the this keyword in their return are the problem.
If I use Object.defineProperty the this keyword is wrong, unless I do it inside the constructor, but it would recreate the property on each instance of the class and slow my code down even further.
This works (I just messed up the syntax in my previous attempt):
// Class
function FooBar (options) {
this.options = options;
}
//Prototype getters
Object.defineProperty(FooBar.prototype, 'a', {
get: function() {
return this.options.a;
}
});
Object.defineProperty(FooBar.prototype, 'b', {
get: function() {
return this.options.b;
}
});
Object.defineProperty(FooBar.prototype, 'ab', {
get: function() {
return this.options.a + this.options.b;
}
});
// Methods
FooBar.prototype.displayOptions = function() {
console.log(this.options);
};
// Code
var options = {
a:'foo',
b:'bar'
};
var fooBar = new FooBar (options);
console.log(fooBar.a);
console.log(fooBar.b);
console.log(fooBar.ab);
fooBar.displayOptions();
For those who are curious about the benefits of converting scripts like this to run faster: Run following code and look to your output in the console (Chrome - 66% faster, Firefox - no difference (curious, since I got the warning from Firefox)):
// WITHOUT PROTOTYPING
var Person1 = function() {
this.name = 'myName';
this.changeName = function(name) {
this.name = name;
};
this.changeName2 = function(name) {
this.name = name;
};
this.changeName3 = function(name) {
this.name = name;
};
this.changeName4 = function(name) {
this.name = name;
};
}
// WITH PROTOTYPING, WITH MUTATION
var Person2 = function() {
this.name = 'myName';
}
Person2.prototype = {
changeName: function(name) {
this.name = name;
},
changeName2: function(name) {
this.name = name;
},
changeName3: function(name) {
this.name = name;
},
changeName4: function(name) {
this.name = name;
}
};
// WITH PROTOTYPING, WITHOUT MUTATION
var Person3 = function() {
this.name = 'myName';
}
Person3.prototype.changeName = function(name) {
this.name = name;
};
Person3.prototype.changeName2 = function(name) {
this.name = name;
};
Person3.prototype.changeName3 = function(name) {
this.name = name;
};
Person3.prototype.changeName4 = function(name) {
this.name = name;
};
// DO THE TEST
var i=0, len=1000000;
// TEST1
window.performance.mark('mark_test_start');
for(i=0;i<len;i++) {
p = new Person1();
p.changeName('myName2');
}
window.performance.mark('mark_test_end');
window.performance.measure('no-prototyping', 'mark_test_start', 'mark_test_end');
// TEST2
window.performance.mark('mark_test2_start');
for(i=0;i<len;i++) {
p = new Person2();
p.changeName('myName2');
}
window.performance.mark('mark_test2_end');
window.performance.measure('prototyping-with-mutation', 'mark_test2_start', 'mark_test2_end');
// TEST3
window.performance.mark('mark_test3_start');
for(i=0;i<len;i++) {
p = new Person2();
p.changeName('myName2');
}
window.performance.mark('mark_test3_end');
window.performance.measure('prototyping-without-mutation', 'mark_test3_start', 'mark_test3_end');
// OUTPUT tests
var items = window.performance.getEntriesByType('measure');
for (var i = 0; i < items.length; ++i) {
var req = items[i];
console.log(req.name + ': ' + req.duration.toFixed(2));
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am trying to implement inheritance in javascript. I came up with following minimal code to support it.
function Base(){
this.call = function(handler, args){
handler.call(this, args);
}
}
Base.extend = function(child, parent){
parent.apply(child);
child.base = new parent;
child.base.child = child;
}
Experts, please let me know if this will be sufficient or any other important issue I may have missed. Based on similar issues faced please suggest other changes.
Here is complete test script:
function Base(){
this.call = function(handler, args){
handler.call(this, args);
}
this.superalert = function(){
alert('tst');
}
}
Base.extend = function(child, parent){
parent.apply(child);
child.base = new parent;
child.base.child = child;
}
function Child(){
Base.extend(this, Base);
this.width = 20;
this.height = 15;
this.a = ['s',''];
this.alert = function(){
alert(this.a.length);
alert(this.height);
}
}
function Child1(){
Base.extend(this, Child);
this.depth = 'depth';
this.height = 'h';
this.alert = function(){
alert(this.height); // display current object height
alert(this.a.length); // display parents array length
this.call(this.base.alert);
// explicit call to parent alert with current objects value
this.call(this.base.superalert);
// explicit call to grandparent, parent does not have method
this.base.alert(); // call parent without overriding values
}
}
var v = new Child1();
v.alert();
alert(v.height);
alert(v.depth);
To implement javascript inheritance in ECMAScript 5 you can define the prototype of an object and use Object.create to inherit. You can also add/override properties as much as you want.
Example:
/**
* Transform base class
*/
function Transform() {
this.type = "2d";
}
Transform.prototype.toString = function() {
return "Transform";
}
/**
* Translation class.
*/
function Translation(x, y) {
// Parent constructor
Transform.call(this);
// Public properties
this.x = x;
this.y = y;
}
// Inheritance
Translation.prototype = Object.create(Transform.prototype);
// Override
Translation.prototype.toString = function() {
return Transform.prototype.toString() + this.type + " Translation " + this.x + ":" + this.y;
}
/**
* Rotation class.
*/
function Rotation(angle) {
// Parent constructor
Transform.call(this);
// Public properties
this.angle = angle;
}
// Inheritance
Rotation.prototype = Object.create(Transform.prototype);
// Override
Rotation.prototype.toString = function() {
return Transform.prototype.toString() + this.type + " Rotation " + this.angle;
}
// Tests
translation = new Translation(10, 15);
console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false
console.log(translation.toString()) // Transform2d Translation 10:15
I think Crockfords solution is too complicated, as is John's. It's much simpler to get javascript inheritance than both of them seem to describe. Consider:
//Classes
function A() {
B.call(this);
}
function B() {
C.call(this);
this.bbb = function() {
console.log("i was inherited from b!");
}
}
function C() {
D.call(this);
}
function D() {
E.call(this);
}
function E() {
//instance property
this.id = Math.random()
}
//set up the inheritance chain (order matters)
D.prototype = new E();
C.prototype = new D();
B.prototype = new C();
A.prototype = new B();
//Add custom functions to each
A.prototype.foo = function() {
console.log("a");
};
B.prototype.bar = function() {
console.log("b");
};
C.prototype.baz = function() {
console.log("c");
};
D.prototype.wee = function() {
console.log("d");
};
E.prototype.woo = function() {
console.log("e");
};
//Some tests
a = new A();
a.foo();
a.bar();
a.baz();
a.wee();
a.woo();
console.log(a.id);
a.bbb();
console.log(a instanceof A);
console.log(a instanceof B);
console.log(a instanceof C);
console.log(a instanceof D);
console.log(a instanceof E);
var b = new B();
console.log(b.id)
I've written a complete description of the above solution on my blog.
As I played with JS objects, I found a more minimalistic solution :-) Enjoy!
function extend(b,a,t,p) { b.prototype = a; a.apply(t,p); }
Example
function A() {
this.info1 = function() {
alert("A");
}
}
function B(p1,p2) {
extend(B,A,this);
this.info2 = function() {
alert("B"+p1+p2);
}
}
function C(p) {
extend(C,B,this,["1","2"]);
this.info3 = function() {
alert("C"+p);
}
}
var c = new C("c");
c.info1(); // A
c.info2(); // B12
c.info3(); // Cc
Here is the simplest and I hope the easiest way to understand inheritance in JS. Most helpful this example will be for PHP programmers.
function Mother(){
this.canSwim = function(){
console.log('yes');
}
}
function Son(){};
Son.prototype = new Mother;
Son.prototype.canRun = function(){
console.log('yes');
}
Now the son has one overridden method and one new
function Grandson(){}
Grandson.prototype = new Son;
Grandson.prototype.canPlayPiano = function(){
console.log('yes');
};
Grandson.prototype.canSwim = function(){
console.log('no');
}
Now the grandson has two overridden methods and one new
var g = new Grandson;
g.canRun(); // => yes
g.canPlayPiano(); // => yes
g.canSwim(); // => no
Why not use objects instead of functions :
var Base = {
superalert : function() {
alert('tst');
}
};
var Child = Object.create(Base);
Child.width = 20;
Child.height = 15;
Child.a = ['s',''];
Child.childAlert = function () {
alert(this.a.length);
alert(this.height);
}
var Child1 = Object.create(Child);
Child1.depth = 'depth';
Child1.height = 'h';
Child1.alert = function () {
alert(this.height);
alert(this.a.length);
this.childAlert();
this.superalert();
};
And call it like this :
var child1 = Object.create(Child1);
child1.alert();
This approach is much more cleaner then with functions.
I found this blog explaining why inheritance with functions isn't a proper way to do it in JS : http://davidwalsh.name/javascript-objects-deconstruction
EDIT
var Child can also be written as :
var Child = Object.create(Base, {
width : {value : 20},
height : {value : 15, writable: true},
a : {value : ['s', ''], writable: true},
childAlert : {value : function () {
alert(this.a.length);
alert(this.height);
}}
});
Here's my solution, which is based on the standard prototypical inheritance method described in Lorenzo Polidori's answer.
First, I start off by defining these helper methods, which make things easier to understand and more readable later on:
Function.prototype.setSuperclass = function(target) {
// Set a custom field for keeping track of the object's 'superclass'.
this._superclass = target;
// Set the internal [[Prototype]] of instances of this object to a new object
// which inherits from the superclass's prototype.
this.prototype = Object.create(this._superclass.prototype);
// Correct the constructor attribute of this class's prototype
this.prototype.constructor = this;
};
Function.prototype.getSuperclass = function(target) {
// Easy way of finding out what a class inherits from
return this._superclass;
};
Function.prototype.callSuper = function(target, methodName, args) {
// If methodName is ommitted, call the constructor.
if (arguments.length < 3) {
return this.callSuperConstructor(arguments[0], arguments[1]);
}
// `args` is an empty array by default.
if (args === undefined || args === null) args = [];
var superclass = this.getSuperclass();
if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");
var method = superclass.prototype[methodName];
if (typeof method != "function") throw new TypeError("TypeError: Object " + superclass.prototype + " has no method '" + methodName + "'");
return method.apply(target, args);
};
Function.prototype.callSuperConstructor = function(target, args) {
if (args === undefined || args === null) args = [];
var superclass = this.getSuperclass();
if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");
return superclass.apply(target, args);
};
Now, not only can you set the superclass of a class with SubClass.setSuperclass(ParentClass), but you can also call overridden methods with SubClass.callSuper(this, 'functionName', [argument1, argument2...]):
/**
* Transform base class
*/
function Transform() {
this.type = "2d";
}
Transform.prototype.toString = function() {
return "Transform";
}
/**
* Translation class.
*/
function Translation(x, y) {
// Parent constructor
Translation.callSuper(this, arguments);
// Public properties
this.x = x;
this.y = y;
}
// Inheritance
Translation.setSuperclass(Transform);
// Override
Translation.prototype.toString = function() {
return Translation.callSuper(this, 'toString', arguments) + this.type + " Translation " + this.x + ":" + this.y;
}
/**
* Rotation class.
*/
function Rotation(angle) {
// Parent constructor
Rotation.callSuper(this, arguments);
// Public properties
this.angle = angle;
}
// Inheritance
Rotation.setSuperclass(Transform);
// Override
Rotation.prototype.toString = function() {
return Rotation.callSuper(this, 'toString', arguments) + this.type + " Rotation " + this.angle;
}
// Tests
translation = new Translation(10, 15);
console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false
console.log(translation.toString()) // Transform2d Translation 10:15
Admittedly, even with the helper functions the syntax here is pretty awkward. Thankfully though, in ECMAScript 6 some syntactic sugar (maximally minimal classes) has been added to make things much prettier. E.g.:
/**
* Transform base class
*/
class Transform {
constructor() {
this.type = "2d";
}
toString() {
return "Transform";
}
}
/**
* Translation class.
*/
class Translation extends Transform {
constructor(x, y) {
super(); // Parent constructor
// Public properties
this.x = x;
this.y = y;
}
toString() {
return super(...arguments) + this.type + " Translation " + this.x + ":" + this.y;
}
}
/**
* Rotation class.
*/
class Rotation extends Transform {
constructor(angle) {
// Parent constructor
super(...arguments);
// Public properties
this.angle = angle;
}
toString() {
return super(...arguments) + this.type + " Rotation " + this.angle;
}
}
// Tests
translation = new Translation(10, 15);
console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false
console.log(translation.toString()) // Transform2d Translation 10:15
Note that ECMAScript 6 is still in the draft stage at this point, and as far as I know is not implemented in any major web browser. However, if you wish you can use something like Traceur compiler to compile ECMAScript 6 down to the plain old ECMAScript 5-based JavaScript. You can see the above example compiled using Traceur here.
While I agree with all above answers, I feel that JavaScript need not be Object Oriented, (Avoid inheritance), instead an object-based approach should be sufficient in most cases.
I like the way Eloquent JavaScript starts its Chapter 8 on Object Oriented Programming talking about OO. Instead of deciphering best way to implement Inheritance, more energy should be devoted to learn functional aspects of JavaScript, hence, I found Chapter 6 on Functional Programming, more interesting.
//This is an example of how to override a method, while preserving access to the original.
//The pattern used is actually quite simple using JavaScripts ability to define closures:
this.somefunction = this.someFunction.override(function(args){
var result = this.inherited(args);
result += this.doSomethingElse();
return result;
});
//It is accomplished through this piece of code (courtesy of Poul Krogh):
/***************************************************************
function.override overrides a defined method with a new one,
while preserving the old method.
The old method is only accessible from the new one.
Use this.inherited() to access the old method.
***************************************************************/
Function.prototype.override = function(func)
{
var remember = this;
var f = function()
{
var save = this.inherited;
this.inherited = remember;
var result = func.apply(this, Array.prototype.slice.call(arguments));
this.inherited = save;
return result;
};
return f;
}
Basic prototypical inheritance
A simple but effective way to do inheritance in JavaScript, is to use the following two-liner :
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
That is similar to doing this :
B.prototype = new A();
The main difference between both is that the constructor of A is not run when using Object.create, which is more intuitive and more similar to class based inheritance.
You can always choose to optionally run the constructor of A when creating a new instance of B by adding adding it to the constructor of B :
function B(arg1, arg2) {
A(arg1, arg2); // This is optional
}
If you want to pass all arguments of B to A, you can also use Function.prototype.apply() :
function B() {
A.apply(this, arguments); // This is optional
}
If you want to mixin another object into the constructor chain of B, you can combine Object.create with Object.assign :
B.prototype = Object.assign(Object.create(A.prototype), mixin.prototype);
B.prototype.constructor = B;
Demo
function A(name) {
this.name = name;
}
A.prototype = Object.create(Object.prototype);
A.prototype.constructor = A;
function B() {
A.apply(this, arguments);
this.street = "Downing Street 10";
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
function mixin() {
}
mixin.prototype = Object.create(Object.prototype);
mixin.prototype.constructor = mixin;
mixin.prototype.getProperties = function() {
return {
name: this.name,
address: this.street,
year: this.year
};
};
function C() {
B.apply(this, arguments);
this.year = "2018"
}
C.prototype = Object.assign(Object.create(B.prototype), mixin.prototype);
C.prototype.constructor = C;
var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());
Creating your own wrapper
If you don't like writing roughly the same two-liner throughout your code, you could write a basic wrapper function like this :
function inheritance() {
var args = Array.prototype.slice.call(arguments);
var firstArg = args.shift();
switch (args.length) {
case 0:
firstArg.prototype = Object.create(Object.prototype);
firstArg.prototype.constructor = firstArg;
break;
case 1:
firstArg.prototype = Object.create(args[0].prototype);
firstArg.prototype.constructor = firstArg;
break;
default:
for(var i = 0; i < args.length; i++) {
args[i] = args[i].prototype;
}
args[0] = Object.create(args[0]);
var secondArg = args.shift();
firstArg.prototype = Object.assign.apply(Object, args);
firstArg.prototype.constructor = firstArg;
}
}
How this wrapper works :
If you pass a one parameter, it's prototype will inherit from Object.
If you pass two parameters, the first's prototype will inherit from the second's.
If you pass more than two parameters, the first's prototype will inherit from the second's and the prototypes of other parameters will be mixed in.
Demo
function inheritance() {
var args = Array.prototype.slice.call(arguments);
var firstArg = args.shift();
switch (args.length) {
case 0:
firstArg.prototype = Object.create(Object.prototype);
firstArg.prototype.constructor = firstArg;
break;
case 1:
firstArg.prototype = Object.create(args[0].prototype);
firstArg.prototype.constructor = firstArg;
break;
default:
for(var i = 0; i < args.length; i++) {
args[i] = args[i].prototype;
}
args[0] = Object.create(args[0]);
var secondArg = args.shift();
firstArg.prototype = Object.assign.apply(Object, args);
firstArg.prototype.constructor = firstArg;
}
}
function A(name) {
this.name = name;
}
inheritance(A);
function B() {
A.apply(this, arguments);
this.street = "Downing Street 10";
}
inheritance(B, A);
function mixin() {
}
inheritance(mixin);
mixin.prototype.getProperties = function() {
return {
name: this.name,
address: this.street,
year: this.year
};
};
function C() {
B.apply(this, arguments);
this.year = "2018"
}
inheritance(C, B, mixin);
var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());
Note
Object.create can be safely used in every modern browser, including IE9+. Object.assign does not work in any version of IE nor some mobile browsers. It is recommended to polyfill Object.create and/or Object.assign if you want to use them and support browsers that do not implement them.
You can find a polyfill for Object.create here
and one for Object.assign here.
How about this simple approach
function Body(){
this.Eyes = 2;
this.Arms = 2;
this.Legs = 2;
this.Heart = 1;
this.Walk = function(){alert(this.FirstName + ' Is Walking')};
}
function BasePerson() {
var BaseBody = new Body(this);
BaseBody.FirstName = '';
BaseBody.LastName = '';
BaseBody.Email = '';
BaseBody.IntroduceSelf = function () { alert('Hello my name is ' + this.FirstName + ' ' + this.LastName); };
return BaseBody;
}
function Person(FirstName,LastName)
{
var PersonBuild = new BasePerson();
PersonBuild.FirstName = FirstName;
PersonBuild.LastName = LastName;
return PersonBuild;
}
var Person1 = new Person('Code', 'Master');
Person1.IntroduceSelf();
Person1.Walk();
//
// try this one:
//
// function ParentConstructor() {}
// function ChildConstructor() {}
//
// var
// SubClass = ChildConstructor.xtendz( ParentConstructor );
//
Function.prototype.xtendz = function ( SuperCtorFn ) {
return ( function( Super, _slice ) {
// 'freeze' host fn
var
baseFn = this,
SubClassCtorFn;
// define child ctor
SubClassCtorFn = function ( /* child_ctor_parameters..., parent_ctor_parameters[] */ ) {
// execute parent ctor fn on host object
// pass it last ( array ) argument as parameters
Super.apply( this, _slice.call( arguments, -1 )[0] );
// execute child ctor fn on host object
// pass remaining arguments as parameters
baseFn.apply( this, _slice.call( arguments, 0, -1 ) );
};
// establish proper prototype inheritance
// 'inherit' methods
SubClassCtorFn.prototype = new Super;
// (re)establish child ctor ( instead of Super ctor )
SubClassCtorFn.prototype.constructor = SubClassCtorFn;
// return built ctor
return SubClassCtorFn;
} ).call( this, SuperCtorFn, Array.prototype.slice );
};
// declare parent ctor
function Sup( x1, x2 ) {
this.parent_property_1 = x1;
this.parent_property_2 = x2;
}
// define some methods on parent
Sup.prototype.hello = function(){
alert(' ~ h e l l o t h e r e ~ ');
};
// declare child ctor
function Sub( x1, x2 ) {
this.child_property_1 = x1;
this.child_property_2 = x2;
}
var
SubClass = Sub.xtendz(Sup), // get 'child class' ctor
obj;
// reserve last array argument for parent ctor
obj = new SubClass( 97, 98, [99, 100] );
obj.hello();
console.log( obj );
console.log('obj instanceof SubClass -> ', obj instanceof SubClass );
console.log('obj.constructor === SubClass -> ', obj.constructor === SubClass );
console.log('obj instanceof Sup -> ', obj instanceof Sup );
console.log('obj instanceof Object -> ', obj instanceof Object );
//
// Object {parent_property_1: 99, parent_property_2: 100, child_property_1: 97, child_property_2: 98}
// obj instanceof SubClass -> true
// obj.constructor === SubClass -> true
// obj instanceof Sup -> true
// obj instanceof Object -> true
//
The easiest way to use AWeb library. Official sample:
/**
* A-class
*/
var ClassA = AWeb.class({
public : {
/**
* A-class constructor
*/
constructor : function() {
/* Private variable */
this.variable1 = "A";
this.calls = 0;
},
/**
* Function returns information about the object
*/
getInfo : function() {
this.incCalls();
return "name=" + this.variable1 + ", calls=" + this.calls;
}
},
private : {
/**
* Private function
*/
incCalls : function() {
this.calls++;
}
}
});
/**
* B-class
*/
var ClassB = AWeb.class({
extends : ClassA,
public : {
/**
* B-class constructor
*/
constructor : function() {
this.super();
/* Private variable */
this.variable1 = "B";
},
/**
* Function returns extended information about the object
*/
getLongInfo : function() {
return this.incCalls !== undefined ? "incCalls exists" : "incCalls undefined";
}
}
});
/**
* Main project function
*/
function main() {
var a = new ClassA(),
b = new ClassB();
alert(
"a.getInfo " + (a.getInfo ? "exists" : "undefined") + "\n" +
"a.getLongInfo " + (a.getLongInfo ? "exists" : "undefined") + "\n" +
"b.getInfo " + (b.getInfo ? "exists" : "undefined") + "\n" +
"b.getLongInfo " + (b.getLongInfo ? "exists" : "undefined") + "\n" +
"b.getInfo()=" + b.getInfo() + "\n" +
"b.getLongInfo()=" + b.getLongInfo()
);
}
I found a solution much easier than extend and prototyping things. Actually I don't know how efficient this is though it looks clean and functional.
var A = function (p) {
if (p == null) p = this;
p.a1 = 0;
this.a2 = 0;
var a3 = 0;
};
var B = function (p) {
if (p == null) p = this;
p.b1 = new A(this);
this.b2 = new A(this);
var b3 = new A(this);
this b4 = new A();
};
var a = new A ();
var b = new B ();
result:
a
a1 0
a2 0
b
a1 0
b1
a2 0
b2
a2 0
b4
a1 0
a2 0
practical example:
var Point = function (p) {
if (p == null) p = this;
var x = 0;
var y = 0;
p.getPoint = function () { return [x,y]; };
p.setPoint = function (_x,_y) { x = _x; y = _y; };
};
var Dimension = function (p) {
if (p == null) p = this;
var w = 0;
var h = 0;
p.getDimension = function() { return [w,h] };
p.setDimension = function(_w,_h) { w = _w; h = _h };
};
var Rect = function (p) {
if (p == null) p = this;
var dimension = new Dimension(this);
var location = new Point(this);
};
var rect = new Rect ();
rect.setDimension({w:30,h:40});
rect.setPoint({x:50,y:50});
In the following implementation of the mediator pattern why this.name in the initialize method always undefined? As I was expecting it to be TestObject. How can I achieve this?
Also how can I create new instances of TestObject?
Mediator = function() {
var debug = function() {
// console.log or air.trace as desired
};
var components = {};
var broadcast = function(event, args, source) {
var e = event || false;
var a = args || [];
if (!e) {
return;
}
//debug(["Mediator received", e, a].join(' '));
for (var c in components) {
if (typeof components[c]["on" + e] == "function") {
try {
//debug("Mediator calling " + e + " on " + c);
var s = source || components[c];
components[c]["on" + e].apply(s, a);
} catch (err) {
debug(["Mediator error.", e, a, s, err].join(' '));
}
}
}
};
var addComponent = function(name, component, replaceDuplicate) {
if (name in components) {
if (replaceDuplicate) {
removeComponent(name);
} else {
throw new Error('Mediator name conflict: ' + name);
}
}
components[name] = component;
};
var removeComponent = function(name) {
if (name in components) {
delete components[name];
}
};
var getComponent = function(name) {
return components[name] || false;
};
var contains = function(name) {
return (name in components);
};
return {
name : "Mediator",
broadcast : broadcast,
add : addComponent,
rem : removeComponent,
get : getComponent,
has : contains
};
}();
// Components
Mediator.add('TestObject', function() {
var someNumber = 0; // sample variable
var someString = 'another sample variable';
return {
onInitialize: function() {
// this.name is automatically assigned by the Mediator
alert(this.name + " initialized.");
},
onFakeEvent: function() {
someNumber++;
alert("Handled " + someNumber + " times!");
},
onSetString: function(str) {
someString = str;
alert('Assigned ' + someString);
}
}
}());
Mediator.broadcast("Initialize");
Mediator.broadcast('FakeEvent');
Mediator.broadcast('SetString', ['test string']);
Mediator.broadcast('FakeEvent');
Mediator.broadcast('SessionStart');
It's because in the function bloc you're returning, this represents the bloc itself, not the mediator object (you can try a console.log(this); in onInitialize to see that).
EDIT:
To add a name component to your callback, you could do something like that
var addComponent = function(varName, component, replaceDuplicate) {
if (varName in components) {
if (replaceDuplicate) {
removeComponent(varName);
} else {
throw new Error('Mediator name conflict: ' + varName);
}
}
components[varName] = component;
components[varName].name = varName;
};
There were a lot of name, so i changed the local name to varName
When I override the clone() method of a Backbone.Model, is there a way to call this overriden method from my implantation? Something like this:
var MyModel = Backbone.Model.extend({
clone: function(){
super.clone();//calling the original clone method
}
})
You'll want to use:
Backbone.Model.prototype.clone.call(this);
This will call the original clone() method from Backbone.Model with the context of this(The current model).
From Backbone docs:
Brief aside on super: JavaScript does not provide a simple way to call
super — the function of the same name defined higher on the prototype
chain. If you override a core function like set, or save, and you want
to invoke the parent object's implementation, you'll have to
explicitly call it.
var Note = Backbone.Model.extend({
set: function(attributes, options) {
Backbone.Model.prototype.set.apply(this, arguments);
...
}
});
You can also use the __super__ property which is a reference to the parent class prototype:
var MyModel = Backbone.Model.extend({
clone: function(){
MyModel.__super__.clone.call(this);
}
});
Josh Nielsen found an elegant solution for this, which hides a lot of the ugliness.
Just add this snippet to your app to extend Backbone's model:
Backbone.Model.prototype._super = function(funcName){
return this.constructor.prototype[funcName].apply(this, _.rest(arguments));
}
Then use it like this:
Model = Backbone.model.extend({
set: function(arg){
// your code here
// call the super class function
this._super('set', arg);
}
});
Working from the answers given by geek_dave and charlysisto, I wrote this to add this._super(funcName, ...) support in classes that have multiple levels of inheritance. It's worked well in my code.
Backbone.View.prototype._super = Backbone.Model.prototype._super = function(funcName) {
// Find the scope of the caller.
var scope = null;
var scan = this.__proto__;
search: while (scope == null && scan != null) {
var names = Object.getOwnPropertyNames(scan);
for (var i = 0; i < names.length; i++) {
if (scan[names[i]] === arguments.callee.caller) {
scope = scan;
break search;
}
}
scan = scan.constructor.__super__;
}
return scan.constructor.__super__[funcName].apply(this, _.rest(arguments));
};
A year later I've fixed some bugs and made things faster. Below is the code that I use now.
var superCache = {};
// Hack "super" functionality into backbone.
Backbone.View.prototype._superFn = Backbone.Model.prototype._superFn = function(funcName, _caller) {
var caller = _caller == null ? arguments.callee.caller : _caller;
// Find the scope of the caller.
var scope = null;
var scan = this.__proto__;
var className = scan.constructor.className;
if (className != null) {
var result = superCache[className + ":" + funcName];
if (result != null) {
for (var i = 0; i < result.length; i++) {
if (result[i].caller === caller) {
return result[i].fn;
}
}
}
}
search: while (scope == null && scan != null) {
var names = Object.getOwnPropertyNames(scan);
for (var i = 0; i < names.length; i++) {
if (scan[names[i]] === caller) {
scope = scan;
break search;
}
}
scan = scan.constructor.__super__;
}
var result = scan.constructor.__super__[funcName];
if (className != null) {
var entry = superCache[className + ":" + funcName];
if (entry == null) {
entry = [];
superCache[className + ":" + funcName] = entry;
}
entry.push({
caller: caller,
fn: result
});
}
return result;
};
Backbone.View.prototype._super = Backbone.Model.prototype._super = function(funcName) {
var args = new Array(arguments.length - 1);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i + 1];
}
return this._superFn(funcName, arguments.callee.caller).apply(this, args);
};
Then given this code:
var A = Backbone.Model.extend({
// className: "A",
go1: function() { console.log("A1"); },
go2: function() { console.log("A2"); },
});
var B = A.extend({
// className: "B",
go2: function() { this._super("go2"); console.log("B2"); },
});
var C = B.extend({
// className: "C",
go1: function() { this._super("go1"); console.log("C1"); },
go2: function() { this._super("go2"); console.log("C2"); }
});
var c = new C();
c.go1();
c.go2();
The output in the console is this:
A1
C1
A2
B2
C2
What's interesting is that class C's call to this._super("go1") scans the class hierarchy until it gets a hit in class A. Other solutions do not do this.
P.S. Uncomment the className entries of the class definitions to enable caching of the _super lookup. (The assumption is that these class names will be unique in the application.)
If you want just to call this._super(); without passing the function name as an argument
Backbone.Controller.prototype._super = function(){
var fn = Backbone.Controller.prototype._super.caller, funcName;
$.each(this, function (propName, prop) {
if (prop == fn) {
funcName = propName;
}
});
return this.constructor.__super__[funcName].apply(this, _.rest(arguments));
}
Better use this plugin:
https://github.com/lukasolson/Backbone-Super
I believe you can cache the original method (although not tested):
var MyModel = Backbone.Model.extend({
origclone: Backbone.Model.clone,
clone: function(){
origclone();//calling the original clone method
}
});
backbone._super.js, from my gists: https://gist.github.com/sarink/a3cf3f08c17691395edf
// Forked/modified from: https://gist.github.com/maxbrunsfeld/1542120
// This method gives you an easier way of calling super when you're using Backbone in plain javascript.
// It lets you avoid writing the constructor's name multiple times.
// You still have to specify the name of the method.
//
// So, instead of having to write:
//
// var Animal = Backbone.Model.extend({
// word: "",
// say: function() {
// return "I say " + this.word;
// }
// });
// var Cow = Animal.extend({
// word: "moo",
// say: function() {
// return Animal.prototype.say.apply(this, arguments) + "!!!"
// }
// });
//
//
// You get to write:
//
// var Animal = Backbone.Model.extend({
// word: "",
// say: function() {
// return "I say " + this.word;
// }
// });
// var Cow = Animal.extend({
// word: "moo",
// say: function() {
// return this._super("say", arguments) + "!!!"
// }
// });
(function(root, factory) {
if (typeof define === "function" && define.amd) {
define(["underscore", "backbone"], function(_, Backbone) {
return factory(_, Backbone);
});
}
else if (typeof exports !== "undefined") {
var _ = require("underscore");
var Backbone = require("backbone");
module.exports = factory(_, Backbone);
}
else {
factory(root._, root.Backbone);
}
}(this, function(_, Backbone) {
"use strict";
// Finds the next object up the prototype chain that has a different implementation of the method.
var findSuper = function(methodName, childObject) {
var object = childObject;
while (object[methodName] === childObject[methodName]) {
object = object.constructor.__super__;
}
return object;
};
var _super = function(methodName) {
// Keep track of how far up the prototype chain we have traversed, in order to handle nested calls to `_super`.
this.__superCallObjects__ || (this.__superCallObjects__ = {});
var currentObject = this.__superCallObjects__[methodName] || this;
var parentObject = findSuper(methodName, currentObject);
this.__superCallObjects__[methodName] = parentObject;
// If `methodName` is a function, call it with `this` as the context and `args` as the arguments, if it's an object, simply return it.
var args = _.tail(arguments);
var result = (_.isFunction(parentObject[methodName])) ? parentObject[methodName].apply(this, args) : parentObject[methodName];
delete this.__superCallObjects__[methodName];
return result;
};
// Mix in to Backbone classes
_.each(["Model", "Collection", "View", "Router"], function(klass) {
Backbone[klass].prototype._super = _super;
});
return Backbone;
}));
In the case that you don't know what the parent class is exactly (multiple inheritance or you want a helper function) then you can use the following:
var ChildModel = ParentModel.extend({
initialize: function() {
this.__proto__.constructor.__super__.initialize.apply(this, arguments);
// Do child model initialization.
}
});
With helper function:
function parent(instance) {
return instance.__proto__.constructor.__super__;
};
var ChildModel = ParentModel.extend({
initialize: function() {
parent(this).initialize.apply(this, arguments);
// Do child model initialization.
}
});
Pass the parent class as an option during instantiation:
BaseModel = Backbone.Model.extend({
initialize: function(attributes, options) {
var self = this;
this.myModel = new MyModel({parent: self});
}
});
Then in your MyModel you can call parent methods like this
this.options.parent.method();
Keep in mind this creates a retain cycle on the two objects. So to let the garbage collector do it's job you would need to manually destroy the retain on one of the objects when finished with it. If you're application is pretty large. I would encourage you to look more into hierarchal setups so events can travel up to the correct object.
2 functions below, one requires you pass in the function name, the other can "discover" which function we want the super version of
Discover.Model = Backbone.Model.extend({
_super:function(func) {
var proto = this.constructor.__super__;
if (_.isUndefined(proto[func])) {
throw "Invalid super method: " + func + " does not exist in prototype chain.";
}
return proto[func].apply(this, _.rest(arguments));
},
_superElegant:function() {
t = arguments;
var proto = this.constructor.__super__;
var name;
for (name in this) {
if (this[name] === arguments.callee.caller) {
console.log("FOUND IT " + name);
break;
} else {
console.log("NOT IT " + name);
}
}
if (_.isUndefined(proto[name])) {
throw "Super method for: " + name + " does not exist.";
} else {
console.log("Super method for: " + name + " does exist!");
}
return proto[name].apply(this, arguments);
},
});
Here is how I would do this:
ParentClassName.prototype.MethodToInvokeName.apply(this);
so for your example this is:
Model.prototype.clone.apply(this)