Prototypes and property inheritence in JavaScript - javascript

I am struggling accessing a property that is set on a child object and accessing it via method on its prototype.
var Parent = function () {
this.getColor = function () {
return this.color;
};
};
var Child = function () {
this.color = red;
};
Child.prototype = new Parent;
var Test = new Child();
console.log(Test.getColor());
=> undefined
Any and all assistance is appreciated.

Here's how I'd do it
function Parent(color) {
function getColor() {
return color;
}
// export public functions
this.getColor = getColor;
}
Now for the Child
function Child(color) {
Parent.call(this, color);
}
Child.prototype = Object.create(Parent.prototype, {
constructor: {value: Child}
});
Let's see it work
var c = new Child("red");
c.getColor(); // "red";
Explanation:
The important bits of the Child constructor
Make sure to call the Parent constructor with the context of the Child instance (this)
Parent.call(this, color);
Setup the Child.prototype based off of the Parent.prototype
Child.prototype = Object.create(Parent.prototype, {
constructor: {value: Child}
});
You can see the node.js implementation of util.inherits uses a similar method.
This somewhat complicated line does two things for you. 1) It avoids invoking the parent constructor unnecessarily, 2) It sets the constructor property properly.
var c = new Child("red");
c instanceof Child; // true
c instanceof Parent; // true
c.constructor.name; // "Child"
But using your code, you would see
var c = new Child("red");
c instanceof Child; // true
c instanceof Parent; // true
c.constructor.name; // "Parent"
This may or may not be a concern for you, but depending on how you want to use your parent/child objects, it may be hard to programmatically differentiate which objects are from the Parent constructor and which ones are from the Child constructor.
Ok, let's see another way to do it by assigning the color property on the object itself
function Parent(color) {
this.color = color;
}
We'll add the getColor method directly to the Parent.prototype
Parent.prototype.getColor = function getColor() {
return this.color;
};
The Child constructor will stay the same. Keep in mind we'll use the same inheritance pattern we used above
function Child(color) {
Parent.call(this, color);
}
Child.prototype = Object.create(Parent.prototype, {
constructor: {value: Child}
});
Lastly, let's get the color using our getColor method
var c = new Child("red");
c.getColor(); // "red"
Or you could access the property on the object directly
c.color; // "red"

Related

Call parent prototype from child prototype

My parent class is
function Parent() {}
Parent.prototype.get = function() {}
Parent.prototype.start= function() { this._start() }
My child is
function Child(){ Parent.call(this, arguments) }
Child.prototype._start = function(){ this.get() /* error here - this.get is not a function*/ }
util.inherits(Child, Parent);
When I do
new Child().start()
I got an error this.get is not a function. How can I call parent prototype function? Thanks.
As the use of util.inherits is discouraged, you should use extends for classes, but you seem to have just regular functions, which means you can set the prototype of the child to the same as the parent before starting to extend it further
function Parent() {}
Parent.prototype.get = function() {
console.log('works fine');
}
Parent.prototype.start = function() {
this._start();
}
function Child() {
Parent.call(this, arguments);
}
Child.prototype = Parent.prototype;
Child.prototype._start = function() {
this.get();
}
var instance = new Child();
instance.start();
Note that Parent and Child now have the same prototype, so by changing one, you'd be changing the other as well.
If for some reason you have to avoid that, using Object.create (or assign) would do that
Child.prototype = Object.create(Parent.prototype);

Javascript: How to extend class properly

Searching over the internet I'm always bumping on this approach of Javascript classes extension
function extend(Child, Parent) {
var F = function() { }
F.prototype = Parent.prototype
Child.prototype = new F()
Child.prototype.constructor = Child
Child.superclass = Parent.prototype
}
But how is that different from this one?
function extend(Child, Parent) {
var p = new Parent()
Child.prototype = p
Child.prototype.constructor = Child
Child.superclass = p
}
This last one also works perfect. So why should I use this extra var F = function() { } move then?
Invoking the original constructor directly can have undesirable side effects, like not working properly if certain expected arguments are not passed.
That's why they use a "proxy" function, which lets you get a new object that inherits from Parent() without actually invoking Parent().
Here's a simple example:
function Person(name, age) {
if (name === undefined)
throw "A name is required";
this.name = name + "";
this.age = age;
}
If Person is the parent, it'll throw an error because there was no name passed.
The first example is (as cookie monster mentioned in the comment) a shim for the following piece of code which might be easier to understand.:
function extend(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.superclass = Parent.prototype;
}
Basically, this implementation makes the object that all Child instances inherit from (Child.prototype) inherit from the object that all Parent instances inherit from (Parent.prototype). Intuitively this is the most accurate representation of class inheritance JavaScript provides.
The second implementation of extends is flawed, because all Child instances will inherit from a specific Parent instance. Should there be significant differences between Parent instances (due to the parameters passed to the constructor for example), the Child instances can not accurate represent that, because they all inherit from a Parent instance created by calling the Parent constructor with no arguments.
Here is an example of what the first implementation can do and the second one can not:
function Parent(name, age) {
this.name = name;
this.age = age;
}
Parent.prototype.greet = function() { return 'I am parent ' + this.name; }
function Child(name){
Parent.call(this, name, 20); // notice the call to the superclass
}
extend(Child, Parent);
Parent.prototype.greet = function() { return 'I am child ' + this.name + ' and i\'m ' + this.age; }
var c = new Child('Tom');
console.log(c.greet()); // I am child Tom and i'm 20
As a sidenote, in the Child constructor i have called the Parent constructor. This is actually quite common when dealing with classical inheritance, so that's another point for the first implementation. It isn't actually required, the Child constructor can safely ignore calling the Parent constructor, but keep in mind that that call basically ensures that the new object created is a valid Parent instance before being a child Instance. In my example if you were to not call the Parent constructor, the name and age properties would not be set on the Child instance, so the greet method would return I am child undefined and i'm undefined, far from what you would expect.
It's worthwhile exploring the different ways you can extend and add bits to an object in JavaScript.
Using constructors
(function (global) {
function SuperClass() { }
var p = SuperClass.prototype;
p.doSomething = function() {
console.log('do something (super)')
};
function OtherClass() {
SuperClass.call(this);
}
OtherClass.prototype = new SuperClass();
Window.OtherClass = OtherClass;
}(window));
var o = new OtherClass();
Using object.create (no double instantiation) - Not supported on all browsers.
(function (global) {
// SuperClass - superclass
function SuperClass() {
}
var p = SuperClass.prototype;
p.doSomething = function() {
console.log('do something (super)')
};
function OtherClass() {
SuperClass.call(this);
}
OtherClass.prototype = Object.create(SuperClass.prototype);
Window.OtherClass = OtherClass;
}(window));
Functional Mixins:
When you want to mixin a generic set of methods/properties into an object.
var mixin = function () {
this.methodA = function () {
};
this.methodA = function () {
};
return this;
}
var object = function () {
this.methodB = function () {
}
}
mixin.call(object.prototype);
A very good details explanation of all the methods:
http://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/

Extend Kinetc.Shape and all derived shapes

I want to extend the object Kinetic.Shape (from which every other shape extends) with some more properties and methods.
What I tried was
Kinetic.Util.addMethods(Kinetic.Shape, {
foo: 'bar'
});
So say if I created a new Kinetic.Circle instance, it should contain this defined property ( and every other shape should do so to).
new Kinetic.Circle(options).foo; // returns undefined
// should return 'bar'
How can I achieve this behaviour?
Waiting for merge this pull request https://github.com/ericdrowell/KineticJS/pull/497.
Now you can do this - replace Kinetic.Util.extend function with this one:
extend: function(child, parent) {
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
var old_proto = child.prototype;
child.prototype = new ctor();
for (var key in old_proto) {
if (old_proto.hasOwnProperty(key))
child.prototype[key] = old_proto[key];
}
child.__super__ = parent.prototype;
}

Can I Write an "Extend" Inheritance Function in Javascript?

I'm looking to simplify inheritance in Javascript a bit. From what I've gathered so far, a good way to achieve "inheritance" between "classes" is as follows:
function ParentClass() {
//Parent Constructor
}
ChildClass.prototype = new ParentClass(); //Step 1: Use parent as prototype
ChildClass.prototype.constructor = ChildClass; //Step 2: Designate appropriate constructor
function ChildClass() {
ParentClass.call(this, arguments); //Step 3: Call the parent's constructor from the child's
//Child Constructor
}
I like to divide the process into three "steps" as I labeled above (Step 1, 2 and 3). I would like to put all three of these steps into one function (coming from a Java background, I've labeled it "extend") that I can call from the function constructor object, like so:
function ParentClass() {
//Parent Constructor
}
ChildClass.extend(ParentClass); //Execute steps 1, 2 and 3 all in this function
function ChildClass() {
//Child Constructor
}
This is what I have so far:
Function.prototype.extend = function (parent) {
var oldConstructor = this.prototype.constructor;
this.prototype = new parent(); //Step 1
this.prototype.constructor = function (arguments) { //Step 2
parent.apply(this, arguments); //Step 3
oldConstructor(arguments);
};
}
Steps 1 and 2 of the extend function work fine in this context, but Step 3 is giving me issues. What I am attempting to do is replace the Child's constructor function with a new function that calls the parent Constructor, and then the Child's constructor. However when I run this the parent constructor is not being called. I haven't been able to nail down the problem (am I using the "this" keyword correctly?); perhaps I am approaching this the wrong way. It is possible to make a function that does this, right? How can I make a working "extend" function?
UPDATE:
The real problems seems to lie with my use of the "this" keyword. Here is the code I am looking at now:
function ParentClass(x) {
this.value = x;
}
function ChildClass() {
}
ChildClass.extend(ParentClass);
function testtest() {
var a = new ParentClass("hello world"); //Alerts "hello world"
alert(a.value);
var b = new ChildClass("hello world"); //Alerts "undefined"
alert(b.value);
}
Why does the first alert work and second does not? I thought that "this" refers to the context in which a function is running, which in both cases would be the object calling the constructor (a or b).
If you really want to do this, perhaps you should just use Coffeescript. Or at least get some ideas from it.
It provides support for classes and inheritance transparently on top of Javascript, and does it using pretty much the same ideas you are using here.
If this is an academic exercise, by all means go ahead (and check out how Coffeescript does it for ideas). But otherwise, there's no need to reinvent the wheel.
For a direct comparison, paste the following into http://js2coffee.org/
class Shape
area: -> undefined
name: -> "Shape"
class Rectangle extends Shape
constructor: (w, h) ->
#w = w
#h = h
area: ->
#w * #h
name: -> "Rectangle" + super
A Rectangle's name() would now return RectangleShape. The name thing is silly, but gets you an idea of how super works.
What it looks like in JS (note all the plumbing in the __extends function):
var Rectangle, Shape,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
Shape = (function() {
function Shape() {}
Shape.prototype.area = function() {
return void 0;
};
Shape.prototype.name = function() {
return "Shape";
};
return Shape;
})();
Rectangle = (function(_super) {
__extends(Rectangle, _super);
function Rectangle(w, h) {
this.w = w;
this.h = h;
}
Rectangle.prototype.area = function() {
return this.w * this.h;
};
Rectangle.prototype.name = function() {
return "Rectangle" + Rectangle.__super__.name.apply(this, arguments);
};
return Rectangle;
})(Shape);
Noticed that the code in your 2nd block does not execute the steps in the same order. When you declare the function after calling extend, it overrides the constructor that is created by the extend function. Try declaring your child class first, and then extending it:
This works for me:
function Parent() {
console.log("Parent Constructor");
}
function Child() {
console.log("Child Constructor");
}
Child.extend(Parent);
new Child()
Outputs:
Parent Constructor
Child Constructor

set attribute with javascript super method [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why are my JS object properties being overwritten by other instances
Why isn't the attribute "t" changed after setT was called? I would expect "4" as output, but it prints "default".
function Car(i) {
var id = i;
var t = "default";
this.getT = function() { return t; }
this.setT = function(p) {
t = p; // attribute t isn't changed ..
}
}
function ECar(id) {
Car.call(this, id); // super constructor call
this.setT = function(p) { // override
ECar.prototype.setT.call(this, p); // super call
}
}
ECar.prototype = new Car();
ecar = new ECar(3);
ecar.setT(4);
alert(ecar.getT()); // prints default, not 4
ECar.prototype = new Car();
At this line ECar's prototype get a context, in which all ECar's instance will be shared.
ECar.prototype.setT.call(this, p);
This line will call at that context, not what has been created while calling super at Car.call(this, id);.
You can fix your code with
function ECar(id) {
Car.call(this, id); // super constructor call
var carSetT = this.setT;
this.setT = function(p) {
carSetT.call(this, p);
}
}
but it would be better (and more readable) to use real prototypes, such as
function Car() {}
Car.prototype.getT = function () { /* ... */ };
Car.prototype.setT = function () { /* ... */ };
function ECar() {}
ECar.prototype = new Car();
ECar.prototype.setT = function () { /* ... */ };
Edit: note (as #Bergi suggested)
You should only use Child.prototype = new Parent() as inheritance if you must support legacy browsers & then you should only use empty constructors.
The most (other-language) compatible way in JavaScript for inheritance is
Child.prototype = Object.create(Parent.prototype)
(MDN says it is supprted from IE 9)
// attribute t isn't changed ..
Please notice that t is not an "attribute", but a variable local to the constructors scope ("private").
ECar.prototype.setT.call(this, p); // super call
does not work how you expect it. You seem to want to change the variable created with the call to your super constructor (it's still local to that variable environment, and exposed by the getT and setT functions that were created in the constructor. So now, you are calling the function that was created in the line ECar.prototype = new Car(); - which changes the variable t that was created there. That you call the function on the current object does not matter, as it does not use the this keyword inside.
So, you don't want to a) use the method of that prototype Car, but your own and b) don't want to create an instance of Car for the prototype at all. See also What is the reason [not] to use the 'new' keyword here?. To apply the super constructor on your current instance is enough. If you want to extend the methods while still using the old ones, you need to preserve them (and exactly them) in a variable.
function Car(id) {
var t = "default";
this.getT = function () {
return t;
};
this.setT = function (p) {
t = p;
};
}
function ECar(id) {
Car.call(this, id); // super constructor call
var oldSetter = this.setT;
this.setT = function (p) { // override
oldSetter(p); // call the function which access this instance's "t"
}
}
ECar.prototype = Object.create(Car.prototype, {constructor: {value: ECar}});
var ecar = new ECar(3);
ecar.setT(4);
console.log(ecar.getT()); // prints 4
function Car(i) {
var id = i;
var t = "default";
this.getT = function() { return t; }
this.setT = function(p) {
t = p; // attribute t isn't changed ..
}
}
function ECar(id) {
Car.call(this, id); // super constructor call
}
ECar.prototype = new Car();
ECar.prototype.constructor = ECar; //Never forget doing this
ecar = new ECar(3);
ecar.setT(4);
alert(ecar.getT());
You don't need to override setT function. ​

Categories

Resources