Here is a simple example of what I want :
var ConstBuilder = function() {
var constructor = function() {} ;
constructor.prototype = {} ;
return constructor ;
} ;
ConstBuilder.prototype = {
add : function(name, value) {
this.prototype[name] = value ;
}
} ;
var A = new ConstBuilder() ;
A.add('test', function() {
console.log('test') ;
}) ;
var a = new A() ;
a.test() ;
This code will fail as A is not an instance of ConstBuilder (because A comes from a returned var constructor = function() {} and won't have the methods defined in its prototype (add).
But this would be useful to modify the super constructor's prototype to have things like :
ConstBuilder.prototype.remove = function(name) {
delete this.prototype[name] ;
} ;
A.remove('test') ;
a.test ; // undefined
Is there a way to have a function as an instance of another ? So this function may implicitely "inherit" all the methods defined in its constructor's prototype.
Or if you have other suggestions, I aim to build modulable constructors - as instances with prototypes are.
Please make sure you have understood the difference between the .prototype property and the internal inheritance-prototype.
The code will fail as A is not an instance of ConstBuilder. Is there a way to have a function as an instance of another?
A is, as every constructor needs to be, a Function. So if you just define your add and remove methods on the Function.prototype, it will work:
Function.prototype.add = function(name, value) {
this.prototype[name] = value;
};
Function.prototype.remove = function(name) {
delete this.prototype[name];
};
function A() {}
A.add('test', function(){console.log('test');});
var a = new A();
a.test(); // test
A.remove('test');
a.test; // undefined
There is no possibility however to let a function inherit from something else than Function.prototype - see Can a JavaScript object have a prototype chain, but also be a function?. If you don't want to modify the native Function.prototype object, you still can use the mixin pattern:
var Constr = (function() {
function add(name, value) {
this.prototype[name] = value;
}
function remove(name) {
delete this.prototype[name];
}
return function mixin(c) {
c.add = add;
c.remove = remove;
return c;
};
})();
var A = Constr(function() {…});
A.add("test", …);
var a = new A();
a.test(); // test
I aim to build modulable constructors
You could use the builder pattern, as you just have seem to tried.
function ConstBuilder() {
this.prototype = {};
};
ConstBuilder.prototype = {
add: function(name, value) {
this.prototype[name] = value;
},
remove: function(name) {
delete this.prototype[name];
},
getConstructor: function() {
var constructor = function() {};
constructor.prototype = this.prototype;
this.prototype.constructor = constructor;
return constructor;
}
};
var A = new ConstBuilder().add('test', function() {
console.log('test');
}).getConstructor();
var a = new A();
a.test(); // test
To remove functions later, you would need to save a reference to the builder.
I think that you are looking for an example of how to do JavaScript's "prototypical inheritance". When JavaScript looks for a property on an object, it first checks the object itself. Next it checks the prototype. However, since everything in JavaScript is an object and the prototype is an object
function Root(){}
Root.prototype.fromRoot = function() { console.log("I'm on Root's prototype."); };
function Child(){}
Child.prototype = new Root();
Child.prototype.fromChild = function() { console.log("I'm on Child's prototype."); };
var r = new Root();
var c = new Child();
r.fromRoot(); // works
c.fromRoot(); // works
c.fromChild(); // works
r.fromChild(); // fails
function a (x,y,construct)
{
if (!construct) return;
this.x=x;
this.y=y;
}
a.prototype.methoda=function ()
{
return x+y;
}
function b (x,y,d,e)
{
a.call (this,x,y,true) //--- this would inherit all own Objects and Properties of a and become own properties of b
this.d=d;
this.e=e;
}
b.prototype=new a (); //--- this would only inherit the prototype, construct becomes false and isnt worked through, which if not would result in adding propertiy x and y to prototype instead of directly to instance of b,
b.prototype.constructor=b;
var test=new b (1,2,3,4);
b.methoda ();
second way
function a (x,y)
{
if (arguments.callee.doNotConstruct) return;
this.x=x;
this.y=y;
}
a.prototype.methoda=function ()
{
return x+y;
}
function b (x,y,d,e)
{
a.call (this,x,y) //--- this would inherit all own Objects and Properties of a and become own properties of b
this.d=d;
this.e=e;
}
a.doNotConstruct=true;
b.prototype=new a (); //--- this would only inherit the prototype, construct becomes false and isnt worked through, which if not would result in adding propertiy x and y to prototype instead of directly to instance of b,
a.doNotConstruct=false;
b.prototype.constructor=b;
var test=new b (1,2,3,4);
b.methoda ();
put this in a function
function prototypeInheritance (inheritor,parent)
{
parent.doNotConstruct=true;
inheritor=new parent ();
inheritor.prototype.constructor=inheritor;
inheritor.parent=parent;
parent.doNotConstruct=false;
}
you can call the parent property with (arguments.callee.parent) in the inheritor constructor and you can check doNotConstruct with arguments.callee.doNotConstruct in the parent constructor
Related
I'm having a bit of a dilemma getting my head around JS' prototypal inheritance. What I'm trying to do is:
Define an object called mod
var mod = function() {
function sayGoodbye() {
alert("Goodbye!");
}
function saySomethingElse(message) {
alert(message);
}
return {
sayGoodbye: sayGoodbye,
saySomethingElse: saySomethingElse
};
};
Define a prototype object called proto
var proto = {
sayHello: function() {
alert("Hello!");
}
};
Set the prototype of mod to proto
mod.prototype = proto;
Call a function that constructs a new instance of mod with the proto prototype
function construct(constructor, args) {
function constructorWrapper() {
return constructor.apply(this, args)
}
constructorWrapper.prototype = constructor.prototype;
return new constructorWrapper();
}
var foo = construct(mod, ["Other Message 1"]);
var bar = construct(mod, ["Other Message 2"]);
console.dir(foo);
console.dir(bar);
The construct function creates a new instance of mod correctly using the apply function but it's prototype is not proto. What am I missing that prevents mod from being constructed with proto as it's prototype?
Here is a fiddle with the above code.
Thanks heaps!!
The reason the .prototype assignment isn't working for you is because setting the prototype chain like this only works when you use the new operator on a constructor function.
You created a factory function that returns a newly created object. Get rid of the return in mod and use this to attach your method and use new operator when creating instances of mod will make the .prototype assignment work.
This might be confusing so I updated your fiddle:
https://jsfiddle.net/6fdo649y/1/
There are several ways to achieve what you are trying to do, but this example explains why you don't see .prototype work.
//Constructor function using this
function Mod(arg1) {
this.sayGoodbye = function sayGoodbye() {
alert("Goodbye!");
}
this.saySomethingElse = function saySomethingElse(message) {
alert(message);
}
this.arg1 = arg1;
};
var proto = {
sayHello: function() {
alert("Hello!");
}
};
Mod.prototype = proto;
function construct(constructor, args) {
function constructorWrapper() {
constructor.apply(this, args)
}
constructorWrapper.prototype = constructor.prototype;
return new constructorWrapper();
}
var foo = construct(Mod, ["Other Message 1"]);
var bar = construct(Mod, ["Other Message 2"]);
console.dir(foo === bar);
console.dir(foo);
console.dir(bar);
edited: added in passing the args through with apply.
I have a method in a base class that I want to keep in a subclass, but just add to it. I've found lots of stuff on augmenting classes and objects with properties and methods, but I can't find, or don't understand, how to just augment the method. The worst case scenario is that I would have to paste the entire method of the parent class into the subclass, but that seems like duplicate code... please help
function someObject (){
this.someProperty = 1;
this.incrementProperty = function incrementProperty(){
this.propertyOfSomeObject += 1;
}
}
function newObject (){
someObject.call(this);
this.incrementProperty = function incrementProperty(){
//do everything the super class has for this property already
return this.someProperty;
}
}
var incrementer = new newObject;
alert (incrementer.incrementProperty()); //I want output to be 2
// parent object
function someObject () {
this.someProperty = 1;
}
// add incrementProperty to the prototype so you're not creating a new function
// every time you instantiate the object
someObject.prototype.incrementProperty = function() {
this.someProperty += 1;
return this.someProperty;
}
// child object
function newObject () {
// we could do useful work here
}
// setup new object as a child class of someObject
newObject.prototype = new someObject();
// this allows us to use "parent" to call someObject's functions
newObject.prototype.parent = someObject.prototype;
// make sure the constructor points to the right place (not someObject)
newObject.constructor = newObject;
newObject.prototype.incrementProperty = function() {
// do everything the super class has for this property already
this.parent.incrementProperty.call(this);
return this.someProperty;
}
var incrementer = new newObject();
alert (incrementer.incrementProperty()); // I want output to be 2
See: http://jsfiddle.net/J7RhA/
this should do, you have to use prototype to have a real concept of oo with javascript
function someObject (){
this.someProperty = 1;
this.propertyOfSomeObject = 0;
this.incrementProperty = function incrementProperty(){
this.propertyOfSomeObject += 1;
return this.propertyOfSomeObject;
}
}
function newObject (){
someObject.call(this);
this.incrementProperty = function incrementProperty(){
this.__super__.incrementProperty.apply(this);
return this.propertyOfSomeObject + 1;
}
}
newObject.prototype = new someObject()
newObject.prototype.__super__ = newObject.prototype
var incrementer = new newObject();
alert(incrementer.incrementProperty()); //I want output to be 2
experiment removing incrementProperty from newObject and it will return 1
I usually use the augment library to write classes in JavaScript. This is how I would rewrite your code using augment:
var Foo = Object.augment(function () {
this.constructor = function () {
this.someProperty = 1;
};
this.incrementProperty = function () {
this.someProperty++;
};
});
var Bar = Foo.augment(function (base) {
this.constructor = function () {
base.constructor.call(this);
};
this.incrementProperty = function () {
base.incrementProperty.call(this);
return this.someProperty;
};
});
As you can see since Bar extends Foo it gets Foo.prototype as a parameter (which we call base). This allows you to easily call the base class constructor and incrementProperty functions. It also shows that the constructor itself is just another method defined on the prototype.
var bar = new Bar;
alert(bar.incrementProperty());
The output will be 2 as expected. See the demo for yourself: http://jsfiddle.net/47gmQ/
From this answer:
Overriding functions
Sometimes children need to extend parent functions.
You want the 'child' (=RussionMini) to do something extra. When RussionMini can call the Hamster code to do something and then do something extra you don't need to copy and paste Hamster code to RussionMini.
In the following example we assume that a Hamster can run 3km an hour but a Russion mini can only run half as fast. We can hard code 3/2 in RussionMini but if this value were to change we have multiple places in code where it needs changing. Here is how we use Hamster.prototype to get the parent (Hamster) speed.
// from goog.inherits in closure library
var inherits = function(childCtor, parentCtor) {
function tempCtor() {};
tempCtor.prototype = parentCtor.prototype;
childCtor.prototype = new tempCtor();
childCtor.prototype.constructor = childCtor;
};
var Hamster = function(name){
if(name===undefined){
throw new Error("Name cannot be undefined");
}
this.name=name;
}
Hamster.prototype.getSpeed=function(){
return 3;
}
Hamster.prototype.run=function(){
//Russionmini does not need to implement this function as
//it will do exactly the same as it does for Hamster
//But Russionmini does need to implement getSpeed as it
//won't return the same as Hamster (see later in the code)
return "I am running at " +
this.getSpeed() + "km an hour.";
}
var RussionMini=function(name){
Hamster.apply(this,arguments);
}
//call this before setting RussionMini prototypes
inherits(RussionMini,Hamster);
RussionMini.prototype.getSpeed=function(){
return Hamster.prototype
.getSpeed.call(this)/2;
}
var betty=new RussionMini("Betty");
console.log(betty.run());//=I am running at 1.5km an hour.
I have saved a property _data in prototype as a definition for all created objects.
function A() {}
A.prototype._data = [];
Now all objects created from A have property _data.
I'd like prototype inheritance, where _data of prototype will have _data values from all prototypes in prototype chain.
Don't know direct way, in this example I use a getter get().
function A() {}
A.prototype._data = [];
A.prototype.add = function(rec) {
this.__proto__._data.push(rec);
}
A.prototype.get = function() {
if(typeof this.__proto__.constructor.prototype.get == 'function')
{
return this.__proto__.constructor.prototype.get().concat(this.__proto__._data);
}
else
{
return this.__proto__._data || [];
}
}
function B() {}
B.prototype = Object.create(A.prototype, { constructor: { value: B }});
B.prototype._data = [];
When I create object a with values aa and object b with value bb, b.get() returns [aa, bb]. And later if _data of prototype A will be extended with aaaa, function b.get() returns [aa, aaaa, bb].
var a = new A(), b = new B();
a.add('aa');
b.add('bb');
console.log(b.get()); // [aa, bb]
a.add('aaaa');
console.log(b.get()); // [aa, aaaa, bb]
// EDITED - _data in A prototype shoud be without B
console.log(a.get()); // [aa, aaaa]
Is it a good (standard) way how to achieve this? I mean using constructor correction while Object.create and reference parent prototype with constructor.prototype?
Here is a demo: http://jsfiddle.net/j9fKP/
Reason for all of this is field definition for scheme in ORM library, where inheritance of schemes is allowed. Child scheme has to have all fields from parent scheme.
I'd like prototype inheritance, where _data of prototype will have _data values from all prototypes in prototype chain.
That's a different thing. "Prototype inheritance" means that if there's a _data property on the current object, it won't go looking further in the chain. Also, it seems to be a kind of issue with nested objects, though I'm not sure what you really want. However, it hardly will make sense to let an array object inherit from another array, if you actually want to concatenate them.
So I think your getter is really fine.
Is it a good (standard) way how to achieve this? I mean using constructor correction while Object.create and reference parent prototype with constructor.prototype
Constructor correction is nice, but actually quite useless (especially if you expect a standard-conform Object.create).
However, in this.__proto__.constructor.prototype either the .__proto__ or the .constructor.prototype is redundant. Since both are either nonstandard or require constructor correction, you should use the standard Object.getPrototypeOf() function to get your prototype object.
With the following very generic solution, you can nest the inheritance (A.proto, B-proto, B-instance, …) arbitrarily deep. Everything inheriting from A.prototype will have an add method which adds _data to the current object, and a get method that traverses the prototype chain and collects all _data:
function A() {
// this._data = []; // why not?
}
A.prototype._data = []; // not even explicitly needed
A.prototype.add = function(rec) {
if (! this.hasOwnProperty("_data")) // add it to _this_ object
this._data = [];
this._data.push(rec);
}
A.prototype.addToAllInstances = function(rec) {
Object.getPrototypeOf(this).add(rec);
}
A.prototype.get = function() {
var proto = Object.getPrototypeOf(this);
var base = typeof proto.get == 'function' ? proto.get() : [];
// maybe better:
// var base = typeof proto.get == 'function' && Array.isArray(base = proto.get()) ? base : [];
if (this.hasOwnProperty("_data"))
return base.concat(this._data); // always get a copy
else
return base;
}
function B() {
A.call(this);
}
B.prototype = Object.create(A.prototype, { constructor: { value: B }});
B.prototype._data = []; // not even explicitly needed
Example usage:
var a = new A();
var b = new B();
a.add('ai');
a.get(); // [ai]
a.addToAllInstances('ap'); // === A.prototype.add('ap');
a.get(); // [ap, ai]
new A().get(); // [ap]
b.get(); // [ap]
b.prototype.get(); // [ap]
b.add('bi');
b.get(); // [ap, bi]
a.addToAllInstances('aap');
b.addToAllInstances('bp');
b.get(); // [ap, aap, bp, bi]
function A() {}
A.prototype._data = [];
A.prototype.add = function(rec) {
this._data.push(rec);
}
A.prototype.get = function() {
return this._data;
}
function B() {}
B.prototype = Object.create(A.prototype, { constructor: { value: B }});
B.prototype._data = [];
B.prototype.get = function() {
return A.prototype._data.concat(this._data);
}
a.add('aa');
b.add('bb');
console.log(b.get()); // [aa, bb]
a.add('aaaa');
console.log(b.get()); // [aa, aaaa, bb]
Fiddle
I think I have a better understanding of what you want to do now, so I've deleted my earlier answer and am posting this one.
Here's how I think I'd do it (with the caveat that I'm not at all sure that with an even better understanding, a completely different approach wouldn't be better):
function A() {}
A.prototype._Adata = [];
A.prototype.add = function(rec) {
this._Adata.push(rec);
};
A.prototype.get = function() {
return this._Adata;
};
function B() {}
B.prototype = Object.create(A.prototype, { constructor: { value: B }});
B.prototype._Bdata = [];
B.prototype.add = function(rec) {
this._Bdata.push(rec);
};
B.prototype.get = function() {
return this._Adata.concat(this._Bdata);
// Or: return A.prototype.get.call(this).concat(this._Bdata);
};
var a = new A();
var b = new B();
a.add('aa');
b.add('bb');
console.log(b.get()); // [aa, bb]
a.add('aaaa');
console.log(b.get()); // [aa, aaaa, bb]
Fiddle
That way, B isn't reaching too deeply into A's internals.
Is it possible in javascript to have a variable that is not able to access out side the class's functions, but is able to be accessed by classes that inherit it? I.E:
class1 has protected var x = 4;
class2 inherits class1;
class2.prototype.getVar = function(){return /* parent, uber, super, whatever */ this.x;};
var cl2 = new class2();
console.log(cl2.x) // undefined
console.log(cl2.getVar()) // 4
No. Prototypal inheritance is limited to properties of objects.
Variables within the constructor are only available to other code in that variable scope.
You could probably come up with something like...
function cls1() {
var a = 'foo';
this.some_func = function() {
alert(a);
};
}
function cls2() {
cls1.apply(this, arguments);
var cls1_func = this.some_func;
var b = 'bar'
this.some_func = function() {
cls1_func.apply(this, arguments);
alert(b);
};
}
var x = new cls2;
x.some_func(); // alert "foo" alert "bar"
Or to make it more specific to your pseudo code...
function class1() {
var x = 4;
this.getVar = function() {
return x;
};
}
function class2() {
class1.apply(this, arguments);
var cls1_get_var = this.getVar;
this.getVar = function() {
return cls1_get_var.apply(this, arguments);
};
}
class2.prototype = Object.create( class1.prototype );
var cl2 = new class2;
console.log(cl2.x) // undefined
console.log(cl2.getVar()) // 4
I think you need to use a closure to achieve what your trying to do. Something like this:
Class1 = function() {
var x = 4;
return {
getVar: function() {
return x;
}
}
} ();// executes the function immediately and returns an
//an object with one method - getVar. Through closure this method
//still has access to the variable x
Class2 = function() { };// define a constructor function
Class2.prototype = Class1;//have it inherit from Class1
Cl2 = new Class2();//instantiate a new instance of Class2
console.log(Cl2.x);//this is undefined
console.log(Cl2.getVar());//this outputs 4
This is one of the neat things about javascript in that you can achieve the same things in javascript as you would in a class based language without all the extra key words. Douglas Crockford (always good to consult about javascript) explains prototypal inheritance here
Edit:
Just had a second look at your question.If you want newly created methods in your class to access the variable in the base class then you would have to call the getVar method within your own method.Like such:
Class2 = function() {
this.getVar2 = function() {
return this.getVar();
}
};
console.log(Cl2.getVar2()) //outputs 4
If subclassing a "class" in JavaScript is done like so:
var ParentClass = function() {
// something
};
var ChildClass = function() {
// something
};
ChildClass.prototype = new ParentClass();
... what should I do when the parent class has required parameters?
var ParentClass = function(requiredParameter) {
if (typeof requiredParameter === 'undefined') {
throw new TypeError("'requiredParameter' is required!");
}
};
var ChildClass = function() {
// something
};
ChildClass.prototype = new ParentClass();
// ^ Throws TypeError
Thanks.
This is how its done:
function Parent( a ) {
this.a = a;
}
function Child( a, b ) {
Parent.call( this, a ); // this is crucial
this.b = b;
}
Child.prototype = Object.create( Parent.prototype );
Child.prototype.constructor = Child;
Live demo: http://jsfiddle.net/ECCgt/ (analyze the instances in the console)
The way you're doing it
ChildClass.prototype = new ParentClass();
is a dirty hack which is broken and should be avoided. Use Object.create to set up the inheritance relationship between the two prototype objects.
The second line
Child.prototype.constructor = Child;
is somewhat optional. We are correcting the constructor property because we had to overwrite Child.prototype in order to set up the inheritance. If you don't care about the constructor property, just leave out that line.
Subclass it like this instead:
function clone (obj) {
if (!obj) return;
clone.prototype = obj;
return new clone();
}
var ParentClass = function() {
// something
};
var ChildClass = function() {
// something
};
ChildClass.prototype = clone(ParentClass.prototype);
ChildClass.prototype.constructor = ChildClass; // if you want
Now you don't have to worry about it, because you don't have to call the parent constructor to subclass it :)
A better way to inherit...
var inherit = (function () {
var F = function () {}; // cache function
return function (C, P) { // Accepts Constructor and Parent
F.prototype = P.prototype;
// faster prototype chain lookup than direct instantiation
C.prototype = new F();
C._super = P.prototype;
C.prototype.constructor = C; // for checking instanceof
};
}());