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

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.

Related

Javascript call prototype function from function inside constructor

I searched for this issue for quite a long time. Din't find any answer to satisfy my question. What I am trying is:
function myClass() {
function privateFunction () {
publicFunction(); //Error
}
}
myClass.prototype.publicFunction = function() {
this.variable = 1;
}
myClass.prototype.publicFunction2= function() {
return this.variable;
}
This is giving me error. I am not getting what the real problem is:
What I tried:
this.publicFunction();
Then:
myClass.publicFunction();
Then:
myClass.prototype.publicFunction();
This works but it overrides for each object. Acts as if it is static across different JS objects.
You haven't declared the prototype functions correctly. You are also missing the this keyword when calling the function publicFunction.
The private function (privateFunction) is not a member of the class, so if you want to call it as a function, you have to specify the context for it.
function myClass() {
function privateFunction () {
this.publicFunction();
}
privateFunction.call(this);
document.write(this.publicFunction2()); // show value in Stackoverflow snippet
}
myClass.prototype.publicFunction = function() {
this.variable = 1;
}
myClass.prototype.publicFunction2 = function() {
return this.variable;
}
var myClassPrototype = new myClass();
Wouldn't a closure be enough?
First, I'd rename myClass to MyClass by convention
function MyClass() {
var myInstance = this;
function privateFunction () {
// closure
myInstance.publicFunction();
}
}
MyClass.prototype.publicFunction = function() {
this.variable = 1;
}
MyClass.prototype.publicFunction2= function() {
return this.variable;
}
Now you should be able to instanciate it this way
var myInstance = new MyClass();
Now you can see that privateFunction is never called, and it woud be a bit redundant to call it, but I just tried to show how to technically achieve it.
Try this:
function myClass() {
function privateFunction(obj) {
obj.privilegedFunction1();
};
this.privilegedFunction1 = function () {
this.variable = 1;
};
this.privilegedFunction2 = function () {
privateFunction(this);
};
}
myClass.prototype.publicFunction2 = function () {
return this.variable;
}
var test = new myClass();
test.privilegedFunction2();
console.log(test.publicFunction2());
And this:
function myClass() {
function privateFunction(obj) {
obj.publicFunction1();
};
this.privilegedFunction2 = function () {
privateFunction(this);
};
}
myClass.prototype.publicFunction1 = function () {
this.variable = 1;
}
myClass.prototype.publicFunction2 = function () {
return this.variable;
}
var test = new myClass();
test.privilegedFunction2();
console.log(test.publicFunction2());
You may want to read some about public vs private vs privileged members in Javascript. Like this article: http://javascript.crockford.com/private.html
Key points:
Public (prototype) members have no access to private.
Privileged (this) members have access to private.
Private function may access privileged and public members through the passed context parameter.
You aren't accessing it because it's inside a private function.
Try it like this:
function myClass() {
function privateFunction () {
}
this.publicFunction = function() {
alert('ok')
}
}
then if you do
var obj = new myClass()
obj.publicFunction()
you can see the alert
In order to inherit the class you will need some other things. Here is a complete example.
Now here is the relevant js code. Put it in a file to test it:
function Operators() {
//mandatory
var self = this
//private
var IPT_X = '#x'
var IPT_Y = '#y'
//public
this.x = 0
this.y = 0
this.showOperators = function() {
//use of a private property (IPT_X) and a public property (this.x)
$(IPT_X).val(this.x)
$(IPT_Y).val(this.y)
}
this.clean = function() {
this.x = 0
this.y = 0
// call to a local public method
this.showOperators()
}
this.updateOperators = function(_x, _y) {
// use of a public property when call from
// derived class method is necessary
self.x = _x
self.y = _y
}
}
function Randomizer() {
// mandatory for derived classes
Operators.call(this)
// mandatory for overloaded methods with call to the inherited method
var parentUpdateOperators = this.updateOperators
var self = this
// private
function getRandomNumber() {
return Math.round(Math.random() * 1000)
}
// public
this.updateOperators = function(_x, _y) {
// call to inherited method of superior class
parentUpdateOperators(_x, _y)
// call to method of superior class
self.showOperators()
}
this.populateRandomNumbers = function() {
// call to public local method (this.updateOperators())
// and to a local private method (getRandomNumber())
this.updateOperators(getRandomNumber(), getRandomNumber())
}
// init
this.populateRandomNumbers()
}
// Mandatory for derived classes. Allows access to superior classes with
// more than 2 levels of inheritance ("grandfather" classes)
Randomizer.prototype = Object.create(Operators.prototype)
function Operations() {
Randomizer.call(this)
var self = this
//private
var IPT_RES = '#res'
var BTN_SUM = '#sum'
var BTN_SUBTRACT = '#subt'
var BTN_MULTIPLY = '#mult'
var BTN_DIVISION = '#div'
var BTN_CLEAN = '#clean'
var BTN_RAND = '#rand'
function calcSum() {
return self.x + self.y
}
function calcSubtraction() {
return self.x - self.y
}
function calcMultiplication() {
return self.x * self.y
}
function calcDivision() {
return self.x / self.y
}
function showRes(val) {
$(IPT_RES).val(val)
}
//public
this.sum = function() {
// call to 2 local private methods
showRes(calcSum())
}
this.subtract = function() {
showRes(calcSubtraction())
}
this.multiply = function() {
showRes(calcMultiplication())
}
this.division = function() {
showRes(calcDivision())
}
// init
$(BTN_SUM).on('click', function() { self.sum() })
$(BTN_SUBTRACT).on('click', function() { self.subtract() })
$(BTN_MULTIPLY).on('click', function() { self.multiply() })
$(BTN_DIVISION).on('click', function() { self.division() })
$(BTN_CLEAN).on('click', function() { self.clean() })
$(BTN_RAND).on('click', function() { self.populateRandomNumbers() })
}
Operations.prototype = Object.create(Randomizer.prototype)
var obj = new Operations()
If you're going to test it here is the html code:
X: <input id='x'>
<br>
Y: <input id='y'>
<br>
Res: <input id='res'>
<br>
<input id='sum' type='button' value='+'>
<input id='subt' type='button' value='-'>
<input id='mult' type='button' value='*'>
<input id='div' type='button' value='/'>
<input id='clean' type='button' value='C'>
<input id='rand' type='button' value='Rand'>
don't forget to add the jquery file.
Here is a JSFiddle with that code in it:
http://jsfiddle.net/vqqrf2cb/24/

What is the best way to access to "this" inside a sub object in javascript class?

This doesn't work because f.bar.bar() in undefined.
var myFunction = function(foo){
this.foo = foo;
this.bar = {
bar: function(){
return this.foo;
}
}
}
var f = new myFunction('foo');
alert(f.bar.bar());
You can always declare a variable in the parent scope:
var myFunction = function(foo){
var func = this;
this.foo = foo;
this.bar = {
bar: function(){
return func.foo;
}
}
}
var f = new myFunction('foo');
alert(f.bar.bar());

Maximum call stack size exceeded in javascript

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/

Accessing prototype method on variable instance

var Foo = (function () {
var cls = function () {
this.prototype = {
sayhi: function () {
alert('hi');
}
};
};
cls.staticMethod = function () {};
return cls;
})();
var f = new Foo();
Why can't i access my sayhi method? Doesn't this refer to the cls variable?
You are attempting to set the prototype property on every instance of cls. What you actually want to do is set the prototype property of cls itself:
var Foo = (function () {
var cls = function () {}; // Constructor function
cls.prototype = { // Prototype of constructor is inherited by instances
sayhi: function () {
alert('hi');
}
};
return cls;
})();

Inheriting a class that has the same constructor but different/similar prototypes

Suppose I have a constructor:
function Constructor(input) {
this.input = input
}
Constructor.prototype.method = function() {
console.log('a')
}
But I want to make another class using a copy of the constructor, but changing the prototypes.
function Constructor2(input) {
this.input = input
}
Constructor2.prototype.method = function() {
console.log('b')
}
I don't want to redefine the constructor. How would you do this? Ideally it would be something as simple as:
var Constructor2 = inherits(Constructor)
Constructor2.prototype.method = // overwrite the inherited `method()`
var inherits = function(childCtor, parentCtor) {
/** #constructor */
function tempCtor() {};
tempCtor.prototype = parentCtor.prototype;
childCtor.superClass_ = parentCtor.prototype;
childCtor.prototype = new tempCtor();
/** #override */
childCtor.prototype.constructor = childCtor;
};
// How to use it:
var Constructor1 = function() {
//add all your methods, variables etc
};
Constructor1.prototype.myMethod = function() {
};
var Contructor2 = function() {
Contructor1.call(this); // Call the super class constructor
};
inherits(Contstructor2, Constructor1);
// Constructor2 now inherits from Constructor1
// override, add methods variables etc, whatever you need.
// Have fun!
Okay, much easier just to use apply:
function newConstructor(Super) {
function Construct() {
Super.apply(this, arguments)
}
require('util').inherits(Construct, Super)
return Construct
}
Here's a nasty-ish solution:
function Constructor1(input) {
this.input = input;
}
Constructor1.prototype.method = function() {
console.log('a');
}
// be careful here: evals the string value of Constructor1 with references to "Constructor1" changed to "Constructor2"
eval(Constructor1.toString().replace("Constructor1", "Constructor2"));
Constructor2.prototype.method = function() {
console.log('b');
}
var c1 = new Constructor1(1);
var c2 = new Constructor2(2);
console.log(c1.constructor === c2.constructor) // true
c1.method() // a
c2.method() // b

Categories

Resources