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
Related
I have a class
function A()
{
var that = this;
var b = new B();
this.setBSize = function(newSize)
{
b.setSize(newSize);
}
};
function B()
{
var that = this;
this.setSize = function(newSize)
{
...
}
}
a = new A();
a.setBSize(5);
How do I avoid writing the setBSize method? How do I expose the public methods of b automatically? I want to do the call like this
a.setSize(5);
Also I need a reference to new B(); which is b inside A()
You could always set the prototype of A to B if you want to inherit all the methods in B
function A() {
var that = this;
};
function B() {
var that = this;
this.setSize = function (newSize) {
console.log(newSize); // 5
}
}
A.prototype = new B();
a = new A();
a.setSize(5);
FIDDLE
In jQuery: $.extend(that, new B());
In angular: angular.extend(that, new B());
function A()
{
var that = this;
$.extend(that, new B());
};
function B()
{
var that = this;
this.setSize = function(newSize)
{
...
}
}
a = new A();
a.setSize(5);
And if you want to use any private variables in B() class define them as var someVar, and all public (overridable) variables as that.somePublicVar
You can use call method for this:
function A() {
var that = this;
B.call(this);
};
function B() {
var that = this;
this.setSize = function (newSize) {
this.size = newSize;
}
}
var a = new A();
a.setSize(5);
Basically you invoke B in context of A, and what happens is that all own properties of the B instance are going to be assigned to this which is A instance. This pattern is called constructor or methods borrowing.
You should utilize prototyping.
make a constructor which shares the function among all the classes(objects):
var myConstructor = function(newSize){
this.setSize = function(newSize)
{
...
}
}
Now you do instanciation:
var a = new myConstructor(someSize);
var b = new myConstrucotr(someSize);
Now with this change a.setSize() is the same as b.setSize()
Using prototype for inheriting the method setSize and discarding all the this and that code.
function B() {
};
function A() {
B.call(this);
};
B.prototype.setSize = function(newSize) {
console.log(newSize);
}
A.prototype = Object.create(B.prototype);
A.prototype.constructor = A;
var a = new A();
a.setSize(5); // 5
console.log(a instanceof A);// true
console.log(a instanceof B);// true
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.
I am trying to get subclass to access parent variable. Can someone tell me what's wrong with this code?
function a() {
this.val = 600;
var self = this;
this.c = new b();
this.d = function() {
console.log("P:");
this.c.p();
}
}
function b() {
this.val2 = 1;
this.p = function() {
console.log(self.val);
}
}
var test = new a();
test.d();
In the b function, self is undefined since it doesn't create a closure. This means you can't reference self.
The way you coded it doesn't create closures.
If you do it like this it works:
http://jsfiddle.net/y2A93/
function a() {
this.val = 600;
var self = this;
this.c = new b();
this.c.self = self; // create `self` variable
this.d = function() {
console.log("P:");
this.c.p();
}
}
function b() {
this.val2 = 1;
this.p = function() {
console.log(this.self.val); // create closure that passes `self` from `b` to `p`.
}
}
var test = new a();
test.d();
What I do is create a self variable in the instance of b called c. Than I create a closure by accessing the self in b from an inner function; p in this case.
Error: self does not exist in the scope of function b. self exists only in scope of a. Try assigning this.c.parent = self (or constructing this.c with that value) and access it from
(new b()).p() as this.parent instead
Try:
function a() {
this.val = 600;
var self = this;
this.c = new b(self);
this.d = function() {
console.log("P:");
this.c.p();
}
}
function b(parent) {
this.val2 = 1;
this.parent = parent;
this.p = function() {
console.log(this.parent.val);
}
}
var test = new a();
test.d();
I write a extend method to achieve inheritance in javascript:
function Class() {}
Class.prototype.create = function () {
var instance = new this();
instance.init();
return instance;
}
// extend method
Class.extend = Class.prototype.extend = function (props) {
var SubClass = function () {};
SubClass.prototype = Object.create(this.prototype);
for (var name in props) {
SubClass.prototype[name] = props[name];
}
SubClass.prototype.constructor = SubClass;
if (this.prototype.init) {
SubClass.prototype.callSuper = this.prototype.init;
}
SubClass.extend = SubClass.prototype.extend;
SubClass.create = SubClass.prototype.create;
return SubClass;
}
// level 1 inheritance
var Human = Class.extend({
init: function () {
}
});
// level 2 inheritance
var Man = Human.extend({
init: function () {
this.callSuper();
}
})
// level 3 inheritance
var American = Man.extend({
init: function () {
this.callSuper();
}
})
// initilization
American.create();
Then the develop tool report Maximum call stack size exceeded
I think the callSuper method cause the problem, callSuper call init, and init call callSuper, both with the same context.
But I don't know how to fixed it!
Can anyone could help me? How to set the correct context?
You have a scope problem. Here is the solution:
function Class() {}
Class.prototype.create = function () {
var instance = new this();
instance.init();
return instance;
}
// extend method
Class.extend = Class.prototype.extend = function (props) {
var SubClass = function () {},
self = this;
SubClass.prototype = Object.create(this.prototype);
for (var name in props) {
SubClass.prototype[name] = props[name];
}
SubClass.prototype.constructor = SubClass;
if (this.prototype.init) {
SubClass.prototype.callSuper = function() {
self.prototype.init();
}
}
SubClass.extend = SubClass.prototype.extend;
SubClass.create = SubClass.prototype.create;
return SubClass;
}
// level 1 inheritance
var Human = Class.extend({
init: function () {
console.log("Human");
}
});
// level 2 inheritance
var Man = Human.extend({
init: function () {
console.log("Man");
this.callSuper();
}
})
// level 3 inheritance
var American = Man.extend({
init: function () {
console.log("American");
this.callSuper();
}
})
// initilization
American.create();
The key moment is to wrap init method in a closure:
SubClass.prototype.callSuper = function() {
self.prototype.init();
}
Here is a jsfiddle containing the solution http://jsfiddle.net/krasimir/vGHUg/6/
var super_class = function(p) {
this.p = p + 1;
this.method = function(a, b) {
// some code
};
};
var base_class = function(o) {
this.o = o;
super_class.call(this, o);
this.method = function(a, b) {
// call super_class .method();
// some code
}
}
base_class.prototype = new super_class();
var bc = new base_class(0);
var v1 = bc.o; // 0
var v2 = bc.p; // 1
How can I call the super_class method when the name and properties are supposed to be identical. If I changed the name, I would just call this.method(3, 4); from within another function. I'm creating an extension class to another extension class, so changing the name of the function will not help me.
Also, storing the function in a private variable var pmethod = this.method; is sloppy at best.
Your current implementation has an error at super_class(this, o);. Either replace it with super_class.call(this, o), or correctly implement an initializer method:
// Basic super class method.
var Super_class = function(p) {
this.init(p); // Call initializer
};
// Define prototype properties and methods
Super_class.prototype = {
constructor: Super_class,
init: function(p) { this.p = p + 1; },
method: function(a, b) {
console.log("Super class method, arguments: " + [a,b]);
}
};
// Define base_class
var Base_class = function(o) {
this.o = o; // Initialize `o` property
this.init(o); // Initialize p variable through the initializer
};
// Extend `Base_class` prototype with `method`.
Base_class.prototype.method = function(a, b) {
// Call the method from the parent = Super_class.prototype.method
this.constructor.prototype.method(a, b);
};
Base_class.prototype = new Super_class; // Set prototype to `super_class`.
var bc = new Base_class(0);
var v1 = bc.o; // 0
var v2 = bc.p; // 1
bc.method('Hi: ', [v1, v2]); // Prints "Super class method, arguments: Hi [0,1]"
Alternatively, you can also push all methods of Base_class in Base_class itself and/or create a reference to the parent class:
// Define base_class
var Base_class = function(o) {
var __super__ = this.constructor.prototype;
this.o = o; // Initialize `o` property
this.init(o); // Initialize p variable through the initializer
Base_class.prototype.method = function(a, b) {
// Call the method from the parent = Super_class.prototype.method
__super__.method(a, b);
};
};
var super_class = function(p) {
this.p = p + 1;
this.method = function(a, b) {
// some code
};
};
var base_class = function(o) {
this.o = o;
super_class(o); // remove "this"
this.method = function(a, b) {
// call base.method();
// some code
}
}
base_class.prototype = new super_class();
base_class.prototype.constructor = base_class; //important: pointing the constructor back to the base class.
This is what the basic inheritance is done in JavaScript. If you want to get something fancy , use
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
See http://javascript.crockford.com/prototypal.html for more information.