JavaScript inheritance and super constructor - javascript

I have found and adapted a JavaScript "class" extend function from coffeescript:
var extend = (function() {
var hasProp = Object.prototype.hasOwnProperty;
function ctor(child) {
this.constructor = child;
}
return function(child, parent) {
for (var key in parent) {
if (hasProp.call(parent, key)) {
child[key] = parent[key];
}
}
ctor.prototype = parent.prototype;
child.prototype = new ctor(child);
child.__super__ = parent.prototype;
// child.prototype.__super__ = parent.prototype; // better?
return child;
};
})();
I am wondering, if there is a reason why they used child.__super__ instead of child.prototype.__super__ (see out-commented code line).
I like the out-commented version more because:
You can access super properties via this.__super__.propertyName instead of ClassName.__super__.propertyName. So you have no redundancy in the class naming.
This makes even more sense for nested inheritance since you can use this.__super__.__super__.propertyName instead of ClassName.__super__.constructor.__super__.propertyName
I do not see any reason for it, but you could even still call "static" functions in a "static" way like that:
ClassName.prototype.__super__.constructor.staticMethod()
Are there any drawbacks with my version that I might have overlooked?
EDIT: I corrected the line to var hasProp = Object.prototype.hasOwnProperty;

Because you're not supposed to use __super__ in your code at all.
It's a compiler artifact, every use of the super macro/keyword/whatever it is will compile to
ClassName.__super__.methodName.call(this, …) // or
ClassName.__super__.methodName.apply(this, …)
// or, in static class functions even
ClassName.__super___.constructor.functionName.call(this, …)
They don't trust the dynamic this binding that you have proposed to use (this.__super__), they rather went for a static reference of the parent. Actually it might have been a good idea not to use a property at all, but just a local super variable in their module scope.
Also, this.__super__ will not work in an inherited method:
function A() { }
A.prototype.method = function() { console.log("works") };
function B() { A.call(this); }
B.prototype = Object.create(A.prototype);
B.prototype.__super__ = A.prototype;
B.prototype.method = function() { this.__super__.method.call(this); }
function C() { B.call(this); }
C.prototype = Object.create(B.prototype);
C.prototype.__super__ = B.prototype;
var b = new B(), c = new C();
b.method() // "works"
c.method() // Maximum recursion depth exceeded
Stack Overflow because you did not get the .__super__ that you expected!

Related

Inheritence in Javascript

I get a strange bug when I implement inheritence in Javascript using prototypes. I am wondering if someone can explain this. In the following code,
I am trying to derive a child class from a parent class:
parent_class=function(byref)
{
if( !parent_class.prototype._vtbl )
{
parent_class.prototype.parent_func= function(o) { return alert("parent_func"); }
parent_class.prototype._vtbl = true;
}
}
child=function(byref)
{
parent_class.call(this,byref);
if( !child.prototype._vtbl )
{
child.prototype = new parent_class;
child.prototype.child_func = parent_class.prototype.parent_func;
child.prototype._vtbl = true;
}
}
function dotest()
{
var pub = new child;
alert( pub.child_func );
var pub2 = new child;
alert( pub2.child_func );
}
dotest();
When you run the test in a browser (Firefox or IE), you get two alerts. The first one says that pub.child_func is undefined, the second one says that the pub.child_func is a valid function and is parent_class.parent_func. Why do you see this behavior. Is this a bug?
Order of execution in javascript of such construct:
function SomeClass () { body(); }
var x = new SomeClass();
is this:
new object which inherits from SomeClass.prototype is created (the prototype for the object is chosen here, before code of the constructor is executed)
body(); gets executed
created object is assigned to x
What you can do in your example is use .__proto__, although you really really should not:
child = function (byref) {
parent_class.call(this, byref);
if (!child.prototype._vtbl) {
child.prototype = new parent_class;
child.prototype.child_func = parent_class.prototype.parent_func;
child.prototype._vtbl = true;
}
this.__proto__ = child.prototype;
}
What you really should do is this:
child = function (byref) {
parent_class.call(this, byref);
}
child.prototype = Object.create(parent_class.prototype);
child.prototype.child_func = parent_class.prototype.parent_func;
child.prototype._vtbl = true;
An easier way to do JavaScript inheritance might be the factory pattern:
function Animal(name) {
return {
run: function() {
alert(name + " is running!")
}
}
}
var animal = Animal("fox");
animal.run();
function Rabbit(name) {
var rabbit = Animal(name);
rabbit.bounce = function() {
this.run();
console.log(name + " bounces");
}
return rabbit;
}
var rabbit = Rabbit("rabbit");
rabbit.bounce();
Source: http://javascript.info/tutorial/factory-constructor-pattern
Short answer: No, it's not browser mistake, it's expected behavior.
Detailed answer:
When a constructor function is called with new, reference to it's prototype is copied into objects's __proto__. Later on this property is used for prototypal lookups for this object.
Your code is really weird from point of view of javascript developer, when you modify prototype of constructor during constructor call execution. However, it works. Because, after var parent = new parent_class(); the following is true parent.__proto__ === parent_class.prototype. It is the SAME reference. Thus adding properties to parent_class.prototype is automatically relfected in parent object via prototypal lookup.
Unfortunately I can't post comments yet, so I have to reference from my answer, #RyszardFiński it is not a correct statement that prototype is defined before contructor called and can't be changed afterwards. It is the same object and unless you change the reference changes will be reflected immediately for all instantiated objects
However in child code in OP ruins references when child.prototype is assigned to a new object.
child.prototype = new parent_class;
child.prototype start pointing a to new instance of parent_class (#1). Instance references look like below
pub.__proto__ === child.prototype
pub2.__proto__ === parentInstance1
child.prototype === parentInstance2
If you remove the line of code where child.prototype is assigned everything will start working as you expect it
pub.__proto__ === child.prototype
pub2.__proto__ === child.prototype
child.prototype === child.prototype
child.prototype has properties _vtbl and child_func

Looking for a JavaScript implementation of node's "util.inherits"

I am implementing a JavaScript library that can also run on node, and I'd like to use node's API as much as possible. My objects emit events, so I found this nice library called eventemitter2, and which reimplements EventEmitter for JavaScript. Now I'd like to find the same for util.inherits. Has anybody heard about such a project ?
Have you tried using the Node.js implementation? (It uses Object.create, so it may or may not work on the browsers you care about). Here's the implementation, from https://github.com/joyent/node/blob/master/lib/util.js:
inherits = function(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
Another method is used by CoffeeScript, which compiles
class Super
class Sub extends Super
to
var Sub, Super,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
Super = (function() {
function Super() {}
return Super;
})();
Sub = (function(_super) {
__extends(Sub, _super);
function Sub() {
return Sub.__super__.constructor.apply(this, arguments);
}
return Sub;
})(Super);
You don't need to use any external library. Just use javascrit as is.
B inherits from A
B.prototype = Object.create (A.prototype);
B.prototype.constructor = B;
And inside the constructor of B:
A.call (this, params...);
If you know that javascript has a property named constructor, then avoid it, no need to hide or not enumerate it, avoid avoid avoid. No need to have a super property, simply use A.call. This is javascript, don't try to use it like any other language because you will miserably fail.

Object constructors building off other Object constructors

I'm currently in the process of converting a quite large actionscript library to work in a nodejs project of mine. While doing so I stumbled upon something that could be an issue: Building classes from classes.
Is there a way to use an object as the base for another object(IE: inherits all members from the base object, then overwrites same name members from the extending object)?
Right now this is what I'm doing, though it's getting a bit difficult to manage now that there are 3+ classes built one on top of another:
// The base object which others may extend
function A() {
this.a = "pie";
}
A.prototype.yum = function() {
return this.a + " is AWESOME!";
}
// The "extends A" object.
// Instead of creating an instance of "B", I current just create an instance of "A",
// then adding the members from "B" to it at which point I return the "A" instance.
function B() {
var a = new A();
a.b = "pie";
// Notice how I have to declare the overwriting function here instead of being able
// to drop it into B's prototype. The reason this bothers me is instead of just
// having one copy of the function(s) stored, each time a "new B" is created the
// function is duplicated... for 100s of "B" objects created, that seems like poor
// memory management
a.yum = function () {
return "I like " + this.a + " and " + this.b;
};
return a;
}
console.log((B()).yum());
Is it possible to do something along the following?
I know this isn't valid, but it gives the idea.
function A(){
this.a = "pie"
}
A.prototype.yum = function () {
return this.a + " is AWESOME!";
}
function B(){
// Throws an "illegal left hand assignment" Exception due to overwriting `this`;
this = new A();
this.b = "cake"
}
B.prototype.yum = function () {
return "I like "+this.a+" and "+this.b;
}
console.log((new B()).yum());
Notes:
1: I know javascript doesn't have classes; it uses objects and prototypes. Otherwise I wouldn't be asking.
2: This isn't the actual code im (trying) to convert; it's a generalized example
3: Please do not suggest a library. I know at times they are valuable, but I'd rather not have to maintain, depend on and include an entire library for the project.
ANSWER:
I know it's bad form to alter native member prototypes, but I think this merits it, due to the lack of possible functionality, and the size of it.
Object.prototype.extendsUpon = function (p) {
var h = Object.prototype.hasOwnProperty;
for(var k in p)if(h.call(p,k))this[k]=p[k];
function c(c){this.constructor=c;}
c.prototype = p.prototype;
this.prototype = new c(this);
this.__base__ = p.prototype;
}
function object_Constructor_built_ontop_of_another_constructor() {
this.extendsUpon(base_Object_to_built_atop_off);
this.__base__.constructor.apply(this, arguments);
// From here proceed as usual
/* To access members from the base object that have been over written,
* use "this.__base__.MEMBER.apply(this, arguments)" */
}
Very much possible. You can do it in multiple ways, the more complete is used in coffeescript:
var ClassBase, ClassTop,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
ClassBase = (function() {
function ClassBase() {}
return ClassBase;
})();
ClassTop = (function(_super) {
__extends(ClassTop, _super);
function ClassTop() {
return ClassTop.__super__.constructor.apply(this, arguments);
}
return ClassTop;
})(ClassBase);
There is going to be some boilerplate code. ClassTop is inheriting everything from ClassBase. The classes don't have much inside them other then an __extend, a (function(_super... and some constructor boilerplate but it's fairly simple.
The inheritance is mostly managed by the __extends boilerplate that does some magic. The full __extends method is beautified here:
__extends = function (child, parent) {
for (var key in parent) {
if (__hasProp.call(parent, key)) child[key] = parent[key];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
};
Again, much less scary then before. You're basically checking properties that the parent has and applying them to the child. More information can be found here: http://www.jimmycuadra.com/posts/coffeescript-classes-under-the-hood

Javascript inheritance and privileged functions

Is it possible to inherit privileged methods in Javascript? In the below, Widget successfully inherits the D function, but not subscribe. Changing the second line in inherit to f.prototype = new base(); seems to work, but I know that's bad for all sorts of reasons. Is there a clean way to do this, or do I have to make everything public? This answer seems to imply that I have to make the methods public (attach to prototype) but I'd like to ask directly.
function EventRaiser() {
var events = {};
this.subscribe = function(key, func) { /* elided */ };
}
EventRaiser.prototype.D = function() { alert("D"); };
function Widget() { }
function Inherit(sub, base) {
function f() { }
f.prototype = base.prototype;
sub.prototype = new f();
sub.prototype.constructor = sub;
}
Inherit(Widget, EventRaiser);
this.subscribe = function(key, func) { /* elided */ };
here your adding a method to the current thisContext.
Inherit(Widget, EventRaiser)
Here your saling the prototype Widget should consume the prototype EventRaiser.
The best you can do is to not mix this.x with prototype.y
Or you can call EventRaiser.call(this) inside function Widget() { } but that's bad style.
If your going to use an inheritance pattern I would recommend you use Object.create & pd :
// prototype
var EventRaiser = {
D: function() { alert("D"); },
subscribe: function(key, func) { ... }
};
// factory
var eventRaiser = function _eventRaiser(proto) {
proto = proto || EventRaiser;
return Object.create(proto, pd({
events: {}
}));
};
// prototype
var Widget = {
...
};
// factory
var widget = function _widget() {
var o = eventRaiser(pd.merge(Widget, EventRaiser));
Object.defineProperties(o, pd({
...
});
return o;
};
Or if you insist Widget should inherit from EventRaiser
var Widget = Object.create(EventRaiser, pd({
...
});
var widget = function _widget() {
var o = eventRaiser(Widget);
Object.defineProperties(o, pd({
...
});
return o;
}
The reasons for recommending this pattern is a clear seperation of the prototype and the factory. This allows you to interact with the prototype without handling the factory. With the use of the new keyword you muddy those waters (as shown in your code) and you also tend to hack this around.
The above code also doesn't look elegant. This means that your realy aught to look for a different pattern. For example EventEmitter from node.js has an explicit check for the this._events object which makes the factory code more elegant.
Your privileged method this.subscribe is only ever attached to an instance of EventRaiser.
This should be obvious when you consider that this line:
this.subscribe = function(...) { } ;
is only ever executed when EventRaiser() is called.
If you don't create an EventRaiser object that property is simply never there to be inherited from.

Crockford-style prototypal pattern gotcha; looking for an elegant solution

I often use Crockford's prototypal pattern when writing JavaScript programs. I thought I understood all the "gotchas" involved, but I discovered one I didn't think about before. I'd like to know if anyone has a best practice for handling it.
Here's a simple example:
// Here's the parent object
var MyObject = {
registry: {},
flatAttribute: null,
create: function () {
var o, F = function () {};
F.prototype = this;
o = new F();
return o;
}
};
// instance is an empty object that inherits
// from MyObject
var instance = MyObject.create();
// Attributes can be set on instance without modifying MyObject
instance.flatAttribute = "This is going to be applied to the instance";
// registry doesn't exist on instance, but it exists on
// instance.prototype. MyObject's registry attribute gets
// dug up the prototype chain and altered. It's not possible
// to tell that's happening just by examining this line.
instance.registry.newAttribute = "This is going to be applied to the prototype";
// Inspecting the parent object
// prints "null"
console.log(MyObject.flatAttribute);
// prints "This is going to be applied to the prototype"
console.log(MyObject.registry.newAttribute);
I want to feel safe that any changes that appear to be made to the instance don't propagate up the inheritance change. This is not the case when the attribute is an object and I'm setting a nested property.
A solution is to re-initialize all object attributes on the instance. However, one of the stated advantages of using this pattern is removing re-initialization code from the constructor. I'm thinking about cloning all the object attributes of the parent and setting them on the instance within the create() function:
{ create: function () {
var o, a, F = function () {};
F.prototype = this;
o = new F();
for (a in this) {
if (this.hasOwnProperty(a) && typeof this[a] === 'object') {
// obviously deepclone would need to be implemented
o[a] = deepclone(this[a]);
}
}
return o;
} };
Is there a better way?
There is a very simple solution to ensuring that they are instance variables only, which is to use the this keyword in the constructor.
var MyObject = {
flatAttribute: null,
create: function () {
var o, F = function () {
this.registry = {}
};
F.prototype = this;
o = new F();
return o;
}
};
this ensures that all properties of "instance.registry.*" are local to the instance because the lookup order for javascript opjects is as follows.
object -> prototype -> parent prototype ...
so by adding a variable to the instance in the constructor function named "registry" that will always be found first.
another solution, which I think is more elegant is to not use crockford's (java style) constructors and use a layout that reflects javascripts object system more naturally. most of those gotchas are from the misfit between practice and language.
// instance stuff
var F = function () {
this.registry = {}
};
F.prototype = {
// static attributes here
flatAttribute: null,
methodA: function(){
// code here 'this' is instance object
this.att = 'blah';
}
};
var instanceA = new F();
instanceA.registry['A'] = 'hi';
var instanceB = new F();
instanceB.registry['B'] = 'hello';
instanceA.registry.A == 'hi'; // true
instanceB.registry.B == 'hello'; // true
F.prototype.registry == undefined; // true
Will this give you the expected result? Here I am not using an Object literal, but an instantly instantiated constructor function for the parent object (Base):
var Base = ( function(){
function MyObject(){
this.registry = {},
this.flatAttribute = null;
if (!MyObject.prototype.create)
MyObject.prototype.create = function(){
return new this.constructor();
};
}
return new MyObject;
} )(),
// create 2 instances from Base
instance1 = Base.create(),
instance2 = Base.create();
// assign a property to instance1.registry
instance1.registry.something = 'blabla';
// do the instance properties really belong to the instance?
console.log(instance1.registry.something); //=> 'blabla'
console.log(instance2.registry.something === undefined); //=> true
But it's all a bit virtual. If you don't want to use the new operator (I think that was te whole idea of it), the following offers you a way to do that without the need for a create method :
function Base2(){
if (!(this instanceof Base2)){
return new Base2;
}
this.registry = {},
this.flatAttribute = null;
if (!Base2.prototype.someMethod){
var proto = Base2.prototype;
proto.someMethod = function(){};
//...etc
}
}
//now the following does the same as before:
var instance1 = Base2(),
instance2 = Base2();
// assign a property to instance1.registry
instance1.registry.something = 'blabla';
// do the instance properties really belong to the instance?
console.log(instance1.registry.something); //=> 'blabla'
console.log(instance2.registry.something === undefined); //=> true
Example in a jsfiddle
I always like to keep in mind that object.Create is one option, and not the only way of achieving non-classical inheritance in javascript.
For myself, I always find that Object.create works best when I want to inherit elements from the parent objects prototype chain (i.e. methods that I'd like to be able to apply to the inheriting object).
--
For simple "Own Property" inheritance, Object.create is largely unnecessary. When I want to inherit own properties, i prefer to use the popular Mixin & Extend patterns (which simply copy one object's own properties to another, without worrying about prototype or "new").
In the Stoyan Stefanov book "Javascript Patterns" he gives an example of a deep extend function that does what you're looking for recursively, and includes support for properties that are arrays as well as standard key/value objects:
function extendDeep(parent, child){
var i,
toStr = Object.prototype.toString,
astr = "[object Array]";
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
if (typeof parent[i] === "object") {
child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
extendDeep(parent[i], child[i]);
} else {
child[i] = parent[i];
}
}
}
return child;
}
If you're using jQuery, jQuery.extend() has an optional "deep" argument that lets you extend an object in near-identical fashion.
i think you're using prototypal inheritance to simulate a classic, Object Oriented inheritance.
What are you trying to do is to stop the prototype method lookup which limits its expressiveness, so why using it? You can achieve the same effect by using this functional pattern:
var MyObject = function() {
// Declare here shared vars
var global = "All instances shares me!";
return {
'create': function() {
var flatAttribute;
var register = {};
return {
// Declare here public getters/setters
'register': (function() {
return register;
})(),
'flatAttribute': (function() {
return flatAttribute;
})(),
'global': (function() {
return global;
})()
};
}
};
}();
var instance1 = MyObject.create();
var instance2 = MyObject.create();
instance1.register.newAttr = "This is local to instance1";
instance2.register.newAttr = "This is local to instance2";
// Print local (instance) var
console.log(instance1.register.newAttr);
console.log(instance2.register.newAttr);
// Print global var
console.log(instance1.global);
console.log(instance2.global);
Code on jsFiddle

Categories

Resources