How can I create a function that inherits from two functions and respects changes for their prototypes when the two base functions don't have an inheritance relationship?
The example demonstrates the behavior I want because c gets modifications to A.prototype and B.prototype.
function A() { }
function B() { }
B.prototype = Object.create(A.prototype);
function C() { }
C.prototype = Object.create(B.prototype);
A.prototype.foo = "foo";
B.prototype.bar = "bar";
var c = new C();
console.log(c.foo); //prints foo
console.log(c.bar); //prints bar
However, I don't have the luxury where B inherits from A.
function A() { }
function B() { }
function C() { }
C.prototype = //something that extends A and B even though B does not extend A.
A.prototype.foo = "foo";
B.prototype.bar = "bar";
var c = new C();
console.log(c.foo); //should print foo
console.log(c.bar); //should print bar
This is not possible.
Try using a mixin pattern, or have a property of C inherit from B and another property inherit from A.
Then access through these properties.
You could change your code to do something like this
C.prototype.perform = function (key) {
var args = Array.prototype.slice(arguments, 1);
if (key in this)
return this[key].apply(this, args);
if (key in B.prototype)
return B.prototype[key].apply(this, args);
if (key in A.prototype)
return A.prototype[key].apply(this, args);
undefined(); // throw meaningful error
}
C.prototype.get = function (key) {
if (key in this)
return this[key];
if (key in B.prototype)
return B.prototype[key];
if (key in A.prototype)
return A.prototype[key];
}
Then use it like
var c = new C();
c.perform('toString');
c.get('foo');
Related
Sorry for dump question I am new to js. I would like to override f2() function in D "class". But for some reason Fire Fox told me: "too much recursion". Could you please point me where recursion happening and how to make this code work as expected?
var B = function () {
};
B.prototype.f2 = function (x) {
return 2 * x;
};
var C = function () {
B.call(this);
};
var D = function () {
C.call(this);
};
D.prototype.f2 = function (x) {
return C.prototype.f2.call(this, x) * 7;
};
inherit(B, C);
inherit(C, D);
function inherit(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
var d = new D();
console.log(d.f2(3));
Two problems:
You need to set up the XYZ.prototype objects before you try to add properties to them. Since your inherit function creates them, you must ensure that you do things in the right order.
You have the order of the parent and child backward in your inherit calls. It's inherit(child, parent), not inherit(parent, child).
var B = function () {
};
B.prototype.f2 = function (x) {
return 2 * x;
};
var C = function () {
B.call(this);
};
inherit(C, B); // *** Moved and updated
var D = function () {
C.call(this);
};
inherit(D, C); // *** Moved and updated
D.prototype.f2 = function (x) {
return C.prototype.f2.call(this, x) * 7;
};
function inherit(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
var d = new D();
console.log(d.f2(3));
The ES2015 version, for comparison:
class B {
f2(x) {
return 2 * x;
}
}
class C extends B {
}
class D extends C {
f2(x) {
return super.f2(x) * 7;
}
}
const d = new D();
console.log(d.f2(3));
How do I splat across objects without using ECMA6 features?
Attempt
function can(arg0, arg1) {
return arg0 + arg1;
}
function foo(bar, haz) {
this.bar = bar;
this.haz = haz;
}
myArgs = [1,2];
With can I can just do:
can.apply(this, myArgs);
When trying with foo:
new foo.apply(this, myArgs);
I get this error (because I'm calling new):
TypeError: function apply() { [native code] } is not a constructor
Using Object.create
function foo(bar, haz) {
this.bar = bar;
this.haz = haz;
}
x = Object.create(foo.prototype);
myArgs = [5,6];
foo.apply(x, myArgs);
console.log(x.bar);
Using Object.create(proto) is the right way to go about this.
Coco and LiveScript (Coffeescript subsets) offer a workaround:
new foo ...args
compiles to
(function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args), t;
return (t = typeof result) == "object" || t == "function" ? result || child : child;
})
(foo, args, function(){});
And in CoffeeScript:
(function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args);
return Object(result) === result ? result : child;
})(foo, args, function(){});
These hacks are ugly, slow, and imperfect; for example, Date relies on its internal [[PrimitiveValue]]. See here.
I tried to make inheritance, but I didn't expect that this.array will act like static member. How can I make it 'protected/public':
function A() {
this.array = [];
}
function B() {
this.array.push(1);
}
B.prototype.constructor=B;
B.prototype = new A();
Firebug:
>>> b = new B();
A { array=[1]}
>>> b = new B();
A { array=[2]}
>>> b = new B()
A { array=[3]}
Not "private/protected", but this will make a new Array for each B.
function A() {
this.array = [];
}
function B() {
A.apply(this); // apply the A constructor to the new object
this.array.push(1);
}
// B.prototype.constructor=B; // pointless
B.prototype = new A();
Is there a way in JavaScript to inherit from a constructor function that returns a function? For example:
var A = function() {
return function(input) {
// do stuff
};
};
var B = function() {};
B.prototype = new A();
var b = new B();
Thanks
By returning a function from your constructor, you're not creating an instance of A, but rather an instance of the function. Therefore, inheritance will not work.
var A = function() { return function(input) {}; };
var a = new A();
>>> typeof a;
"function"
var A = function() {};
var a = new A();
>>> typeof a;
"object"
If you need B to inherit the returned function from A, you should set it as a method of A, either locally or in the prototype chain, and pass it that way.
var A = function() {
this.method = function(input) {}
};
var B = function() {}
B.prototype = new A();
var b = new B();
>>> b.method
'function(input) { }'
function A(){
this.a = {};
this.b = 0;
this.Test = function(value){
this.a.x = value;
this.b = value;
};
}
function B(){}
B.prototype = new A;
var b1= (new B());
b1.Test(1);
var b2= (new B());
b2.Test(2);
log(b1.b == 1); //true
log(b2.b == 2); //true
log(b1.a.x == 1);//false x == 2
log(b2.a.x == 2);//true
Why are instances share field a?
This happens because the a object is shared across all instances of B (since the B prototype's is an instance of A).
A workaround would be to assign a new object in your Test method as an own property that shadows the one available on the prototype chain, for example:
function A(){
this.a = {};
this.b = 0;
this.Test = function(value){
this.a = {x: value}; // shadow the object on the prototype chain
this.b = value;
};
}
function B(){}
B.prototype = new A;
var b1= new B();
b1.Test(1);
var b2= new B();
b2.Test(2);
console.log(b1.b == 1); //true
console.log(b2.b == 2); //true
console.log(b1.a.x == 1);//true
console.log(b2.a.x == 2);//true