Javascript inherited class constructor issue - javascript

I want to create a subclass from a superclass using prototypes in javascript, so I set them up:
var SuperClass = function() {
this.a = 1;
this.get = function() {return this.a;}
this.init = function() {
CreateStrangeThings();
}
this.init();
}
var SubClass = function() {
this.b = 2;
this.get = function() {return this.b;}
}
SubClass.prototype = new SuperClass();
The problem is, the line SubClass.prototype = new SuperClass(); calls the CreateStrangeThings(); function. I want this function to be called only when I create the subclass object (var subOjbect = new SubClass();)
How to overcome this issue? Maybe I should use SubClass.prototype = SuperClass; ? Is it wise?
EDIT:
SubClass.prototype = SuperClass;
removes "a" property from SubClass

The problem is, the line SubClass.prototype = new SuperClass(); calls the CreateStrangeThings(); function.
Yes. That's why that pattern, despite being often-cited, is wrong. Another reason is that it ignores the possibility the superclass constructor may require arguments.
Instead, create the prototype object without calling the super constructor:
SubClass.prototype = Object.create(SuperClass.prototype);
SubClass.prototype.constructor = SubClass;
...and also call the super constructor inside SubClass:
var SubClass = function() {
SuperClass.call(this);
this.b = 2;
this.get = function() {return this.b;}
};
So all together we get:
var SuperClass = function() {
this.a = 1;
this.get = function() {return this.a;}
this.init = function() {
CreateStrangeThings();
}
this.init();
};
var SubClass = function() {
SuperClass.call(this);
this.b = 2;
this.get = function() {return this.b;}
};
SubClass.prototype = Object.create(SuperClass.prototype);
SubClass.prototype.constructor = SubClass;
Or of course, use ES2015 and a transpiler.
class SuperClass {
constructor() {
this.a = 1;
this.get = function() {return this.a;};
this.init = function() {
CreateStrangeThings();
};
this.init();
}
}
class SubClass {
constructor() {
super();
this.b = 2;
this.get = function() {return this.b;};
}
}
How to overcome this issue? Maybe I should use SubClass.prototype = SuperClass; ? Is it wise?
No. If you want objects created via new SubClass to inherit properties from SuperClass.prototype, you need SubClass.prototype to use SuperClass.prototype as its prototype. SuperClass doesn't; the prototype of SuperClass is Function.prototype, not SubClass.prototype. (Ignore the name of the prototype property on functions; it isn't their prototype, it's the prototype new assigns to objects created via new TheFunction.)

Related

JavaScript: Inheritance in ECMAScript5

var A = function () {
this.p1 = 2;
};
A.prototype.f1 = function () {
return 7;
};
var B = function () {
inherit(A, B);
};
function inherit(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
var b = new B();
console.log(b.p1); // get undefined here
I am new to JS, sorry for dump question. I would like to inherit B from A. What am I doing wrong?
You're only calling inherit() after creating the instance of B.
You need to call inherit() statically, once, after defining both functions.
You also need to call A on your instance in B.
For more details on how to properly do inheritance, see my blog.
What am I doing wrong?
Two things:
You're calling inherit inside B. You should be doing it outside.
Inside B, you should be calling A, e.g.
A.call(this/*, other, args, here, if, needed*/);
or
A.apply(this, arguments);
to pass on all of the arguments B received at runtime via the automatic arguments pseudo-array.
Like so:
var A = function () {
this.p1 = 2;
};
A.prototype.f1 = function () {
return 7;
};
var B = function () {
A.call(this); // <==== Added
};
inherit(A, B); // <==== Moved
function inherit(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
var b = new B();
console.log(b.p1); // get 2 here now
You didn't call the base constructor. Also, it's enough if you inherit only once the classes.
var A = function () {
this.p1 = 2;
};
A.prototype.f1 = function () {
return 7;
};
var B = function () {
A.apply(this, arguments);
};
inherit(A, B);
function inherit(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
var b = new B();
console.log(b.p1); // get undefined here

Two subclasses inherit properties of superclass and doesn't lost the scope

For help you help me i'm going to illustrate the problem with an example:
var SuperClass = function() {
this.propertieOfSuperClass = 'A';
this.init();
};
SuperClass.prototype.init = function() {
console.log(this.propertieOfSuperClass); // ouput 'A';
};
// Some code here to do the magic for SubClass1
// Some code here to do the magic for SubClass2
SubClass1:
var SubClass1 = function() {
this.methodOfSubClass1();
};
SubClass1.prototype.methodOfSubClass1 = function() {
console.log(this.propertieOfSuperClass); // output 'A';
};
SubClass2:
var SubClass2 = function() {
this.methodOfSubClass2();
};
SubClass2.prototype.methodOfSubClass = function() {
console.log(this.propertieOfSuperClass); // output 'A';
};
I want be able to have this SuperClass which i set the properties and other two subclasses which i can access the properties of SuperClass, but without lose the scope.
I was trying to use inside of my SuperClass init method:
SubClass1.call(this);
SubClass2.call(this);
And this will make the properties of SuperClass accessible, but the SubClass's will lost their scope, so i cant call methodOfSubClass1 and methodOfSubClass2, because they doesn't exist in the SuperClass.
How could i do that?
var SuperClass = function() {
this.propertieOfSuperClass = 'A';
this.init();
};
SuperClass.prototype.init = function() {
console.log(this.propertieOfSuperClass); // ouput 'A';
};
var SubClass1 = function() {
SuperClass.call(this); // Call parent constructor
this.methodOfSubClass1();
};
SubClass1.prototype = Object.create(SuperClass.prototype); // Inheritance
SubClass1.prototype.methodOfSubClass1 = function() {
console.log(this.propertieOfSuperClass); // output 'A';
};
var SubClass2 = function() {
SuperClass.call(this); // Call parent constructor
this.methodOfSubClass2();
};
SubClass2.prototype = Object.create(SuperClass.prototype); // Inheritance
SubClass2.prototype.methodOfSubClass2 = function() {
console.log(this.propertieOfSuperClass); // output 'A';
};
Simple do:
var SuperClass = function SuperClass() {
this.propertieOfSuperClass = 'A';
this.init();
};
SuperClass.prototype.init = function() {
console.log(this.propertieOfSuperClass); // ouput 'A';
SubClass.call(this);
};
Them:
SuperClass.prototype = Object.create(SubClass.prototype);
Them in the SubClass:
var SubClass = function() {
console.log(this); // output will be the SuperClass
this.methodOfSubClass();
};
The important part is now:
SubClass.prototype.constructor = SubClass;
SubClass1.prototype.methodOfSubClass = function() {
console.log(this.propertieOfSuperClass); // output 'A';
};
You can do the same with SubClass2.

Rewrite javascript function into node.js module

I have this function: (which is I guess abstract factory for creating javascript objects)
var $class = function(definition) {
var constructor = definition.constructor;
var parent = definition.Extends;
if (parent) {
var F = function() { };
constructor._superClass = F.prototype = parent.prototype;
constructor.prototype = new F();
}
for (var key in definition) {
constructor.prototype[key] = definition[key];
}
constructor.prototype.constructor = constructor;
return constructor;
};
A use it for defining classes C/java syntax like with polymorphism and extending:
var Bullet = $class({
Extends: GameObject,
constructor: function(texturePath, x, y, ctx, direction, passable, player) {
GameObject.call(this, texturePath, x, y, ctx, 1, 1, passable, new Array(8, 8, 0, 0));
},
isActive: function() {
},
getPlayer: function() {
},
update: function(dt) {
},
destroy: function() {
},
processCollision: function() {
}
});
And then calling:
var bullet = new Bullet(params);
I tried to rewrite it into nodejs module like this:
(function(){
var $class = function(definition) {
var constructor = definition.constructor;
var parent = definition.Extends;
if (parent) {
var F = function() { };
constructor._superClass = F.prototype = parent.prototype;
constructor.prototype = new F();
}
for (var key in definition) {
constructor.prototype[key] = definition[key];
}
constructor.prototype.constructor = constructor;
return constructor;
};
module.exports.createClass = function() {
return $class();
}
});
And then call it with:
var c = require(__dirname + "\\Class");
var Bullet = c.createClass({
Extends: GameObject,
constructor: function() {}
});
But it doesn't work, can you please help me with rewriting?
UPDATE: I rewrited it from #Salem answer, but I lost extending and polymorphism in process.
In order to have extending I simply have to write instead of
Extends: ParentClass
this:
Extends: ParentClass.constructor
I've expected that polymorphism would be something like:
// in class which is extended from ParentClass
ParentClass.method();
// in parent class adding line
module.exports.method = ParentClass.method;
But this is undefined. So where is the catch?
FINALLY I used mochiscript module for nodejs, it is even better syntax sugar with more object oriented functionality.
In your code, createClass is a function without any parameter. Also you call $class without any paramter also.
You don't need to wrap all your code in a function, because everything you declare there won't be accessible from outside unless you export it. So it should be something like this:
var func = function(definition) {
var constructor = definition.constructor;
var parent = definition.Extends;
if (parent) {
var F = function() { };
constructor._superClass = F.prototype = parent.prototype;
constructor.prototype = new F();
}
for (var key in definition) {
constructor.prototype[key] = definition[key];
}
constructor.prototype.constructor = constructor;
return constructor;
};
module.exports.createClass = func;
This means that if you require this module as X, the only thing you can access is X.createClass, and not X.func or anything else.

Is John Resig's Javascript inheritance snippet deprecated?

I'm looking for a simple way of creating two classes, one inheriting from the other, and the child redefining one of the parent's methods, and inside the new method, calling the parent's.
For example, having a class Animal and Dog, where the Animal class defines a method makeSound() which establishes how to output a sound, which Dog then overrides in its own makeSound() method to make a "woof" sound, but while also calling Animal's makeSound() to output that woof.
I looked at John Resig's model here, but it uses the native arguments.callee property which is apparently depreciated in ECMA script 5. Does that mean I shouldn't use John Resig's code?
What would one neat, simple way of writing my animal/dog code using Javascript's prototype inheritance model?
Does that mean I shouldn't use John Resig's code?
Correct, not when you are using ES5 in strict mode. However, it can be easily adapted:
/* Simple JavaScript Inheritance for ES 5.1
* based on http://ejohn.org/blog/simple-javascript-inheritance/
* (inspired by base2 and Prototype)
* MIT Licensed.
*/
(function(global) {
"use strict";
var fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
function BaseClass(){}
// Create a new Class that inherits from this class
BaseClass.extend = function(props) {
var _super = this.prototype;
// Set up the prototype to inherit from the base class
// (but without running the init constructor)
var proto = Object.create(_super);
// Copy the properties over onto the new prototype
for (var name in props) {
// Check if we're overwriting an existing function
proto[name] = typeof props[name] === "function" &&
typeof _super[name] == "function" && fnTest.test(props[name])
? (function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, props[name])
: props[name];
}
// The new constructor
var newClass = typeof proto.init === "function"
? proto.hasOwnProperty("init")
? proto.init // All construction is actually done in the init method
: function SubClass(){ _super.init.apply(this, arguments); }
: function EmptyClass(){};
// Populate our constructed prototype object
newClass.prototype = proto;
// Enforce the constructor to be what we expect
proto.constructor = newClass;
// And make this class extendable
newClass.extend = BaseClass.extend;
return newClass;
};
// export
global.Class = BaseClass;
})(this);
Prototype chain with Object.create() + assign constructor
function Shape () {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function (x, y) {
this.x += x;
this.y += y;
};
function Rectangle () {
Shape.apply(this, arguments); // super constructor w/ Rectangle configs if any
}
Rectangle.prototype = Object.create(Shape.prototype); // inherit Shape functionality
// works like Rectangle.prototype = new Shape() but WITHOUT invoking the constructor
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
rect instanceof Rectangle && rect instanceof Shape // returns true
from Object.create documentation
information about the new keyword
This is something I came up with for inheritance using chaining as well as allowing _super to work.
/**
* JavaScript simple inheritance
* by Alejandro Gonzalez Sole (base on John Resig's simple inheritance script)
* MIT Licensed.
**/
(function (){
var initializing = false,
fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.* /;
function Class(){};
function inheritClass(superClass){
var self = this;
function Class(){
if (!initializing && typeof this._constructor === 'function')
this._constructor.apply(this, arguments);
}
Class.prototype = superClass.prototype;
Class.prototype._constructor = superClass;
Class.prototype.constructor = Class;
Class.extend = extendClass;
//currenlty if you inhert multiple classes it breaks
Class.inherit = inheritClass;
return Class;
};
function extendClass(prop) {
var self = this;
var _super = self.prototype;
function Class(){
if (!initializing && typeof this._constructor === 'function')
this._constructor.apply(this, arguments);
}
initializing = true;
var prototype = new self();
initializing = false;
for (var name in prop) {
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
this._super = _super[name];
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) : prop[name];
}
Class.prototype = prototype;
Class.prototype.constructor = Class;
Class.extend = extendClass;
Class.inherit = inheritClass;
return Class;
};
Class.extend = extendClass;
Class.inherit = inheritClass;
})();
//EXAMPLE
function Person(){
this.name = "No name";
console.log("PERSON CLASS CONSTRUCTOR")
}
Person.prototype.myMethod = function (t){
console.log("MY PERSON", t, this.name);
return -1;
}
var TestPerson = Class.inherit(Person).extend({
_constructor: function(){
this._super();
this.name = "JOhn";
console.log("TEST PERSON CONSTRUCTOR");
},
myMethod: function (t){
console.log("TEST PERSON", t, this.name);
return this._super(t)
}
});
var test = new TestPerson();
console.log(test.myMethod("BA"));
I've been testing it on my pixi wrapper https://github.com/guatedude2/pixijs-cli so far it's been working very well for me.
The only issue i've encountered with this approach is that you can only inherit once. If you run inherit again it will override the previous inheritance.
I prefer the way TypeScript generates a form of inheritance (Select Simple Inheritance from the dropdown). That one doesn't use arguments.callee, but an __extends prototype.
var __extends = this.__extends || function (d, b) {
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Animal = (function () {
function Animal(name) {
this.name = name;
}
Animal.prototype.move = function (meters) {
alert(this.name + " moved " + meters + "m.");
};
return Animal;
})();
var Snake = (function (_super) {
__extends(Snake, _super);
function Snake(name) {
_super.call(this, name);
}
Snake.prototype.move = function () {
alert("Slithering...");
_super.prototype.move.call(this, 5);
};
return Snake;
})(Animal);
var Horse = (function (_super) {
__extends(Horse, _super);
function Horse(name) {
_super.call(this, name);
}
Horse.prototype.move = function () {
alert("Galloping...");
_super.prototype.move.call(this, 45);
};
return Horse;
})(Animal);
var sam = new Snake("Sammy the Python");
var tom = new Horse("Tommy the Palomino");
sam.move();
tom.move(34);

how to get the actual constructor of a javascript object?

is there a way to get the actual called function used to instance the object?
function A(){}
A.prototype.test = function(){};
function B(){}
B.prototype = Object.create(A.prototype);
B.prototype.test = function(){};
var x = new B();
alert(x.constructor); // alerts "A"
i'm also interested in cross browser support
thanks
After this sort of inheritance, you need to explicitly set the constructor of the 'subclass'.
...
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
...
As far as I'm aware, there is no way to do this automatically. Even Google's Closure library has something like this;
var inherit = function(subClass, superClass) {
var temp = function() {};
temp.prototype = superClass.prototype;
subClass._super = superClass.prototype;
subClass.prototype = new temp();
subClass.prototype.constructor = subClass;
};
So, if you have a constructor with arguments, you can simply do something like
var ParentClass = function(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
};
ParentClass.prototype.show = function() {
console.log('Parent!');
console.log('arg1: ' + this.arg1);
console.log('arg2: ' + this.arg2);
};
var ChildClass = function(arg1, arg2, arg3) {
ParentClass.call(this, arg1, arg2);
this.arg3 = arg3;
};
inherit(ChildClass, ParentClass);
ChildClass.prototype.show = function() {
console.log('Child!');
console.log('arg1: ' + this.arg1);
console.log('arg2: ' + this.arg2);
console.log('arg3: ' + this.arg3);
};
Example.

Categories

Resources