Javascript: How to extend class properly - javascript

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/

Related

OOP JS: Is there point using prototype property in the base object?

Let's say I have the following simple OOP-like implementation:
Implementation 1:
function Base() {
this.text = "lol";
}
Base.prototype.hello = function() {
console.log("Hello from base");
}
function Child() {
}
Child.prototype = new Base(); // All objects created from Child function now have reference to this Base object in their __proto__ property.
Child.prototype.hello = function() { // Changes the hello implementation in the prototype object
console.log("Hello from child");
}
var child1 = new Child();
child1.hello(); // "Hello from child"
This is the implementation I see more often: The methods that are supposed to be inherited (like the hello method) from the Base object to child objects are defined using the prototype property.
However, if I bind the hello method right in to the base object using this keyword I get the same result:
Implementation 2:
function Base() {
this.text = "lol";
this.hello = function() {
console.log("Hello from base");
}
}
function Child() {
}
Child.prototype = new Base(); // All objects created from Child function now have reference to this Base object in their __proto__ property.
Child.prototype.hello = function() { // Changes the hello implementation in the prototype object
console.log("Hello from child");
}
var child1 = new Child();
child1.hello(); // "Hello from child"
What's the difference between these two implementations?
Prototype methods are shared by all the objects under the same class while adding a method to the object itself makes the function private to that specific object.
If you are creating only one object from the class, there is no difference in performance. However, if you are creating more than one object, prototype method will improve performance significantly.
Here is an example
function Base() {
this.text = "lol";
}
Base.prototype.hello = function() {
console.log("Hello from base");
}
var obj1 = new Base();
var obj2 = new Base();
obj1.hello();
obj2.hello();
Base.prototype.hello = function() {
console.log("Bye");
}
obj1.hello();
obj2.hello();
function Base() {
this.text = "lol";
this.hello = function() {
console.log("Hello from base");
};
}
var obj1 = new Base();
var obj2 = new Base();
obj1.hello();
obj2.hello();
obj1.hello = function() {
console.log("Bye");
}
obj1.hello();
obj2.hello();
Basically you are asking: What is the difference between
function Base() {
this.text = "lol";
}
Base.prototype.hello = function() {
console.log("Hello from base");
}
and
function Base() {
this.text = "lol";
this.hello = function() {
console.log("Hello from base");
}
}
Functionally, there is none.
But: In the latter setup every Base instance contains a separate copy of the hello method.
That means
Two object instances will be physically larger than two object instances of the former setup.
With the former setup you can override a method for all live instances in a single step (imagine debugging a large object graph): You simply swap it on the prototype.
With the latter setup you would have to swap out the method on every live instance individually.
Methods in the former setup don't have access to instance variables (those declared with var inside the constructor).
Methods in the latter setup do.
Methods in the prototype setup are inherently public.
Personally I find the prototype setup cleaner: It separates functionality from object instances. It saves memory. It forces you to use sensible scoping.
If you need a function to have access to private instance data (that you do not under any circumstances want to assign to this), then adding that method in the constructor is the only way to do it.
But for all commonly shared functionality I recommend using the prototype.

Inheritence in Javascript

I get a strange bug when I implement inheritence in Javascript using prototypes. I am wondering if someone can explain this. In the following code,
I am trying to derive a child class from a parent class:
parent_class=function(byref)
{
if( !parent_class.prototype._vtbl )
{
parent_class.prototype.parent_func= function(o) { return alert("parent_func"); }
parent_class.prototype._vtbl = true;
}
}
child=function(byref)
{
parent_class.call(this,byref);
if( !child.prototype._vtbl )
{
child.prototype = new parent_class;
child.prototype.child_func = parent_class.prototype.parent_func;
child.prototype._vtbl = true;
}
}
function dotest()
{
var pub = new child;
alert( pub.child_func );
var pub2 = new child;
alert( pub2.child_func );
}
dotest();
When you run the test in a browser (Firefox or IE), you get two alerts. The first one says that pub.child_func is undefined, the second one says that the pub.child_func is a valid function and is parent_class.parent_func. Why do you see this behavior. Is this a bug?
Order of execution in javascript of such construct:
function SomeClass () { body(); }
var x = new SomeClass();
is this:
new object which inherits from SomeClass.prototype is created (the prototype for the object is chosen here, before code of the constructor is executed)
body(); gets executed
created object is assigned to x
What you can do in your example is use .__proto__, although you really really should not:
child = function (byref) {
parent_class.call(this, byref);
if (!child.prototype._vtbl) {
child.prototype = new parent_class;
child.prototype.child_func = parent_class.prototype.parent_func;
child.prototype._vtbl = true;
}
this.__proto__ = child.prototype;
}
What you really should do is this:
child = function (byref) {
parent_class.call(this, byref);
}
child.prototype = Object.create(parent_class.prototype);
child.prototype.child_func = parent_class.prototype.parent_func;
child.prototype._vtbl = true;
An easier way to do JavaScript inheritance might be the factory pattern:
function Animal(name) {
return {
run: function() {
alert(name + " is running!")
}
}
}
var animal = Animal("fox");
animal.run();
function Rabbit(name) {
var rabbit = Animal(name);
rabbit.bounce = function() {
this.run();
console.log(name + " bounces");
}
return rabbit;
}
var rabbit = Rabbit("rabbit");
rabbit.bounce();
Source: http://javascript.info/tutorial/factory-constructor-pattern
Short answer: No, it's not browser mistake, it's expected behavior.
Detailed answer:
When a constructor function is called with new, reference to it's prototype is copied into objects's __proto__. Later on this property is used for prototypal lookups for this object.
Your code is really weird from point of view of javascript developer, when you modify prototype of constructor during constructor call execution. However, it works. Because, after var parent = new parent_class(); the following is true parent.__proto__ === parent_class.prototype. It is the SAME reference. Thus adding properties to parent_class.prototype is automatically relfected in parent object via prototypal lookup.
Unfortunately I can't post comments yet, so I have to reference from my answer, #RyszardFiński it is not a correct statement that prototype is defined before contructor called and can't be changed afterwards. It is the same object and unless you change the reference changes will be reflected immediately for all instantiated objects
However in child code in OP ruins references when child.prototype is assigned to a new object.
child.prototype = new parent_class;
child.prototype start pointing a to new instance of parent_class (#1). Instance references look like below
pub.__proto__ === child.prototype
pub2.__proto__ === parentInstance1
child.prototype === parentInstance2
If you remove the line of code where child.prototype is assigned everything will start working as you expect it
pub.__proto__ === child.prototype
pub2.__proto__ === child.prototype
child.prototype === child.prototype
child.prototype has properties _vtbl and child_func

Prototypes and property inheritence in 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"

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

JavaScript Extending Class

I have a base class:
function Monster() {
this.health = 100;
}
Monster.prototype.growl = function() {
console.log("Grr!");
}
That I want to extend and create another class with:
function Monkey extends Monster() {
this.bananaCount = 5;
}
Monkey.prototype.eatBanana {
this.bananaCount--;
this.health++; //Accessing variable from parent class monster
this.growl(); //Accessing function from parent class monster
}
I've done quite a bit of research and there appears to be many convoluted solutions for doing this in JavaScript. What would be the simplest and most reliable way of accomplishing this in JS?
Updated below for ES6
March 2013 and ES5
This MDN document describes extending classes well:
https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript
In particular, here is now they handle it:
// define the Person Class
function Person() {}
Person.prototype.walk = function(){
alert ('I am walking!');
};
Person.prototype.sayHello = function(){
alert ('hello');
};
// define the Student class
function Student() {
// Call the parent constructor
Person.call(this);
}
// inherit Person
Student.prototype = Object.create(Person.prototype);
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
// replace the sayHello method
Student.prototype.sayHello = function(){
alert('hi, I am a student');
}
// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
alert('goodBye');
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true
Note that Object.create() is unsupported in some older browsers, including IE8:
If you are in the position of needing to support these, the linked MDN document suggests using a polyfill, or the following approximation:
function createObject(proto) {
function ctor() { }
ctor.prototype = proto;
return new ctor();
}
Using this like Student.prototype = createObject(Person.prototype) is preferable to using new Person() in that it avoids calling the parent's constructor function when inheriting the prototype, and only calls the parent constructor when the inheritor's constructor is being called.
May 2017 and ES6
Thankfully, the JavaScript designers have heard our pleas for help and have adopted a more suitable way of approaching this issue.
MDN has another great example on ES6 class inheritance, but I'll show the exact same set of classes as above reproduced in ES6:
class Person {
sayHello() {
alert('hello');
}
walk() {
alert('I am walking!');
}
}
class Student extends Person {
sayGoodBye() {
alert('goodBye');
}
sayHello() {
alert('hi, I am a student');
}
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true
Clean and understandable, just like we all want. Keep in mind, that while ES6 is pretty common, it's not supported everywhere:
ES6 gives you now the opportunity to use class & extends keywords :
Then , your code will be :
You have a base class:
class Monster{
constructor(){
this.health = 100;
}
growl() {
console.log("Grr!");
}
}
That You want to extend and create another class with:
class Monkey extends Monster {
constructor(){
super(); //don't forget "super"
this.bananaCount = 5;
}
eatBanana() {
this.bananaCount--;
this.health++; //Accessing variable from parent class monster
this.growl(); //Accessing function from parent class monster
}
}
Try this:
Function.prototype.extends = function(parent) {
this.prototype = Object.create(parent.prototype);
};
Monkey.extends(Monster);
function Monkey() {
Monster.apply(this, arguments); // call super
}
Edit: I put a quick demo here http://jsbin.com/anekew/1/edit. Note that extends is a reserved word in JS and you may get warnings when linting your code, you can simply name it inherits, that's what I usually do.
With this helper in place and using an object props as only parameter, inheritance in JS becomes a bit simpler:
Function.prototype.inherits = function(parent) {
this.prototype = Object.create(parent.prototype);
};
function Monster(props) {
this.health = props.health || 100;
}
Monster.prototype = {
growl: function() {
return 'Grrrrr';
}
};
Monkey.inherits(Monster);
function Monkey() {
Monster.apply(this, arguments);
}
var monkey = new Monkey({ health: 200 });
console.log(monkey.health); //=> 200
console.log(monkey.growl()); //=> "Grrrr"
If you don't like the prototype approach, because it doesn't really behave in a nice OOP-way, you could try this:
var BaseClass = function()
{
this.some_var = "foobar";
/**
* #return string
*/
this.someMethod = function() {
return this.some_var;
}
};
var MyClass = new Class({ extends: BaseClass }, function()
{
/**
* #param string value
*/
this.__construct = function(value)
{
this.some_var = value;
}
})
Using lightweight library (2k minified): https://github.com/haroldiedema/joii
I can propose one variant, just have read in book, it seems the simplest:
function Parent() {
this.name = 'default name';
};
function Child() {
this.address = '11 street';
};
Child.prototype = new Parent(); // child class inherits from Parent
Child.prototype.constructor = Child; // constructor alignment
var a = new Child();
console.log(a.name); // "default name" trying to reach property of inherited class
This is an extension (excuse the pun) of elclanrs' solution to include detail on instance methods, as well as taking an extensible approach to that aspect of the question; I fully acknowledge that this is put together thanks to David Flanagan's "JavaScript: The Definitive Guide" (partially adjusted for this context). Note that this is clearly more verbose than other solutions, but would probably benefit in the long-term.
First we use David's simple "extend" function, which copies properties to a specified object:
function extend(o,p) {
for (var prop in p) {
o[prop] = p[prop];
}
return o;
}
Then we implement his Subclass definition utility:
function defineSubclass(superclass, // Constructor of our superclass
constructor, // Constructor of our new subclass
methods, // Instance methods
statics) { // Class properties
// Set up the prototype object of the subclass
constructor.prototype = Object.create(superclass.prototype);
constructor.prototype.constructor = constructor;
if (methods) extend(constructor.prototype, methods);
if (statics) extend(constructor, statics);
return constructor;
}
For the last bit of preparation we enhance our Function prototype with David's new jiggery-pokery:
Function.prototype.extend = function(constructor, methods, statics) {
return defineSubclass(this, constructor, methods, statics);
};
After defining our Monster class, we do the following (which is re-usable for any new Classes we want to extend/inherit):
var Monkey = Monster.extend(
// constructor
function Monkey() {
this.bananaCount = 5;
Monster.apply(this, arguments); // Superclass()
},
// methods added to prototype
{
eatBanana: function () {
this.bananaCount--;
this.health++;
this.growl();
}
}
);
For traditional extending you can simply write superclass as constructor function,
and then apply this constructor for your inherited class.
function AbstractClass() {
this.superclass_method = function(message) {
// do something
};
}
function Child() {
AbstractClass.apply(this);
// Now Child will have superclass_method()
}
Example on angularjs:
http://plnkr.co/edit/eFixlsgF3nJ1LeWUJKsd?p=preview
app.service('noisyThing',
['notify',function(notify){
this._constructor = function() {
this.scream = function(message) {
message = message + " by " + this.get_mouth();
notify(message);
console.log(message);
};
this.get_mouth = function(){
return 'abstract mouth';
}
}
}])
.service('cat',
['noisyThing', function(noisyThing){
noisyThing._constructor.apply(this)
this.meow = function() {
this.scream('meooooow');
}
this.get_mouth = function(){
return 'fluffy mouth';
}
}])
.service('bird',
['noisyThing', function(noisyThing){
noisyThing._constructor.apply(this)
this.twit = function() {
this.scream('fuuuuuuck');
}
}])
For Autodidacts:
function BaseClass(toBePrivate){
var morePrivates;
this.isNotPrivate = 'I know';
// add your stuff
}
var o = BaseClass.prototype;
// add your prototype stuff
o.stuff_is_never_private = 'whatever_except_getter_and_setter';
// MiddleClass extends BaseClass
function MiddleClass(toBePrivate){
BaseClass.call(this);
// add your stuff
var morePrivates;
this.isNotPrivate = 'I know';
}
var o = MiddleClass.prototype = Object.create(BaseClass.prototype);
MiddleClass.prototype.constructor = MiddleClass;
// add your prototype stuff
o.stuff_is_never_private = 'whatever_except_getter_and_setter';
// TopClass extends MiddleClass
function TopClass(toBePrivate){
MiddleClass.call(this);
// add your stuff
var morePrivates;
this.isNotPrivate = 'I know';
}
var o = TopClass.prototype = Object.create(MiddleClass.prototype);
TopClass.prototype.constructor = TopClass;
// add your prototype stuff
o.stuff_is_never_private = 'whatever_except_getter_and_setter';
// to be continued...
Create "instance" with getter and setter:
function doNotExtendMe(toBePrivate){
var morePrivates;
return {
// add getters, setters and any stuff you want
}
}
Summary:
There are multiple ways which can solve the problem of extending a constructor function with a prototype in Javascript. Which of these methods is the 'best' solution is opinion based. However, here are two frequently used methods in order to extend a constructor's function prototype.
ES 2015 Classes:
class Monster {
constructor(health) {
this.health = health
}
growl () {
console.log("Grr!");
}
}
class Monkey extends Monster {
constructor (health) {
super(health) // call super to execute the constructor function of Monster
this.bananaCount = 5;
}
}
const monkey = new Monkey(50);
console.log(typeof Monster);
console.log(monkey);
The above approach of using ES 2015 classes is nothing more than syntactic sugar over the prototypal inheritance pattern in javascript. Here the first log where we evaluate typeof Monster we can observe that this is function. This is because classes are just constructor functions under the hood. Nonetheless you may like this way of implementing prototypal inheritance and definitively should learn it. It is used in major frameworks such as ReactJS and Angular2+.
Factory function using Object.create():
function makeMonkey (bananaCount) {
// here we define the prototype
const Monster = {
health: 100,
growl: function() {
console.log("Grr!");}
}
const monkey = Object.create(Monster);
monkey.bananaCount = bananaCount;
return monkey;
}
const chimp = makeMonkey(30);
chimp.growl();
console.log(chimp.bananaCount);
This method uses the Object.create() method which takes an object which will be the prototype of the newly created object it returns. Therefore we first create the prototype object in this function and then call Object.create() which returns an empty object with the __proto__ property set to the Monster object. After this we can initialize all the properties of the object, in this example we assign the bananacount to the newly created object.
the absolutely minimal (and correct, unlike many of the answers above) version is:
function Monkey(param){
this.someProperty = param;
}
Monkey.prototype = Object.create(Monster.prototype);
Monkey.prototype.eatBanana = function(banana){ banana.eat() }
That's all. You can read here the longer explanation

Categories

Resources