How do I create an abstract base class in JavaScript? - javascript

Is it possible to simulate abstract base class in JavaScript? What is the most elegant way to do it?
Say, I want to do something like: -
var cat = new Animal('cat');
var dog = new Animal('dog');
cat.say();
dog.say();
It should output: 'bark', 'meow'

JavaScript Classes and Inheritance (ES6)
According to ES6, you can use JavaScript classes and inheritance to accomplish what you need.
JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance.
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
First of all, we define our abstract class. This class can't be instantiated, but can be extended.
We can also define functions that must be implemented in all classes that extends this one.
/**
* Abstract Class Animal.
*
* #class Animal
*/
class Animal {
constructor() {
if (this.constructor == Animal) {
throw new Error("Abstract classes can't be instantiated.");
}
}
say() {
throw new Error("Method 'say()' must be implemented.");
}
eat() {
console.log("eating");
}
}
After that, we can create our concrete Classes. These classes will inherit all functions and behaviour from abstract class.
/**
* Dog.
*
* #class Dog
* #extends {Animal}
*/
class Dog extends Animal {
say() {
console.log("bark");
}
}
/**
* Cat.
*
* #class Cat
* #extends {Animal}
*/
class Cat extends Animal {
say() {
console.log("meow");
}
}
/**
* Horse.
*
* #class Horse
* #extends {Animal}
*/
class Horse extends Animal {}
And the results...
// RESULTS
new Dog().eat(); // eating
new Cat().eat(); // eating
new Horse().eat(); // eating
new Dog().say(); // bark
new Cat().say(); // meow
new Horse().say(); // Error: Method say() must be implemented.
new Animal(); // Error: Abstract classes can't be instantiated.

One simple way to create an abstract class is this:
/**
#constructor
#abstract
*/
var Animal = function() {
if (this.constructor === Animal) {
throw new Error("Can't instantiate abstract class!");
}
// Animal initialization...
};
/**
#abstract
*/
Animal.prototype.say = function() {
throw new Error("Abstract method!");
}
The Animal "class" and the say method are abstract.
Creating an instance would throw an error:
new Animal(); // throws
This is how you "inherit" from it:
var Cat = function() {
Animal.apply(this, arguments);
// Cat initialization...
};
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.say = function() {
console.log('meow');
}
Dog looks just like it.
And this is how your scenario plays out:
var cat = new Cat();
var dog = new Dog();
cat.say();
dog.say();
Fiddle here (look at the console output).

Do you mean something like this:
function Animal() {
//Initialization for all Animals
}
//Function and properties shared by all instances of Animal
Animal.prototype.init=function(name){
this.name=name;
}
Animal.prototype.say=function(){
alert(this.name + " who is a " + this.type + " says " + this.whattosay);
}
Animal.prototype.type="unknown";
function Cat(name) {
this.init(name);
//Make a cat somewhat unique
var s="";
for (var i=Math.ceil(Math.random()*7); i>=0; --i) s+="e";
this.whattosay="Me" + s +"ow";
}
//Function and properties shared by all instances of Cat
Cat.prototype=new Animal();
Cat.prototype.type="cat";
Cat.prototype.whattosay="meow";
function Dog() {
//Call init with same arguments as Dog was called with
this.init.apply(this,arguments);
}
Dog.prototype=new Animal();
Dog.prototype.type="Dog";
Dog.prototype.whattosay="bark";
//Override say.
Dog.prototype.say = function() {
this.openMouth();
//Call the original with the exact same arguments
Animal.prototype.say.apply(this,arguments);
//or with other arguments
//Animal.prototype.say.call(this,"some","other","arguments");
this.closeMouth();
}
Dog.prototype.openMouth=function() {
//Code
}
Dog.prototype.closeMouth=function() {
//Code
}
var dog = new Dog("Fido");
var cat1 = new Cat("Dash");
var cat2 = new Cat("Dot");
dog.say(); // Fido the Dog says bark
cat1.say(); //Dash the Cat says M[e]+ow
cat2.say(); //Dot the Cat says M[e]+ow
alert(cat instanceof Cat) // True
alert(cat instanceof Dog) // False
alert(cat instanceof Animal) // True

You might want to check out Dean Edwards' Base Class: http://dean.edwards.name/weblog/2006/03/base/
Alternatively, there is this example / article by Douglas Crockford on classical inheritance in JavaScript: http://www.crockford.com/javascript/inheritance.html

Is it possible to simulate abstract base class in JavaScript?
Certainly. There are about a thousand ways to implement class/instance systems in JavaScript. Here is one:
// Classes magic. Define a new class with var C= Object.subclass(isabstract),
// add class members to C.prototype,
// provide optional C.prototype._init() method to initialise from constructor args,
// call base class methods using Base.prototype.call(this, ...).
//
Function.prototype.subclass= function(isabstract) {
if (isabstract) {
var c= new Function(
'if (arguments[0]!==Function.prototype.subclass.FLAG) throw(\'Abstract class may not be constructed\'); '
);
} else {
var c= new Function(
'if (!(this instanceof arguments.callee)) throw(\'Constructor called without "new"\'); '+
'if (arguments[0]!==Function.prototype.subclass.FLAG && this._init) this._init.apply(this, arguments); '
);
}
if (this!==Object)
c.prototype= new this(Function.prototype.subclass.FLAG);
return c;
}
Function.prototype.subclass.FLAG= new Object();
var cat = new Animal('cat');
That's not really an abstract base class of course. Do you mean something like:
var Animal= Object.subclass(true); // is abstract
Animal.prototype.say= function() {
window.alert(this._noise);
};
// concrete classes
var Cat= Animal.subclass();
Cat.prototype._noise= 'meow';
var Dog= Animal.subclass();
Dog.prototype._noise= 'bark';
// usage
var mycat= new Cat();
mycat.say(); // meow!
var mygiraffe= new Animal(); // error!

Animal = function () { throw "abstract class!" }
Animal.prototype.name = "This animal";
Animal.prototype.sound = "...";
Animal.prototype.say = function() {
console.log( this.name + " says: " + this.sound );
}
Cat = function () {
this.name = "Cat";
this.sound = "meow";
}
Dog = function() {
this.name = "Dog";
this.sound = "woof";
}
Cat.prototype = Object.create(Animal.prototype);
Dog.prototype = Object.create(Animal.prototype);
new Cat().say(); //Cat says: meow
new Dog().say(); //Dog says: woof
new Animal().say(); //Uncaught abstract class!

Question is quite old, but I created some possible solution how to create abstract "class" and block creation of object that type.
//our Abstract class
var Animal=function(){
this.name="Animal";
this.fullname=this.name;
//check if we have abstract paramater in prototype
if (Object.getPrototypeOf(this).hasOwnProperty("abstract")){
throw new Error("Can't instantiate abstract class!");
}
};
//very important - Animal prototype has property abstract
Animal.prototype.abstract=true;
Animal.prototype.hello=function(){
console.log("Hello from "+this.name);
};
Animal.prototype.fullHello=function(){
console.log("Hello from "+this.fullname);
};
//first inheritans
var Cat=function(){
Animal.call(this);//run constructor of animal
this.name="Cat";
this.fullname=this.fullname+" - "+this.name;
};
Cat.prototype=Object.create(Animal.prototype);
//second inheritans
var Tiger=function(){
Cat.call(this);//run constructor of animal
this.name="Tiger";
this.fullname=this.fullname+" - "+this.name;
};
Tiger.prototype=Object.create(Cat.prototype);
//cat can be used
console.log("WE CREATE CAT:");
var cat=new Cat();
cat.hello();
cat.fullHello();
//tiger can be used
console.log("WE CREATE TIGER:");
var tiger=new Tiger();
tiger.hello();
tiger.fullHello();
console.log("WE CREATE ANIMAL ( IT IS ABSTRACT ):");
//animal is abstract, cannot be used - see error in console
var animal=new Animal();
animal=animal.fullHello();
As You can see last object give us error, it is because Animal in prototype has property abstract. To be sure it is Animal not something which has Animal.prototype in prototype chain I do:
Object.getPrototypeOf(this).hasOwnProperty("abstract")
So I check that my closest prototype object has abstract property, only object created directly from Animal prototype will have this condition on true. Function hasOwnProperty checks only properties of current object not his prototypes, so this gives us 100% sure that property is declared here not in prototype chain.
Every object descended from Object inherits the hasOwnProperty method. This method can be used to determine whether an object has the specified property as a direct property of that object; unlike the in operator, this method does not check down the object's prototype chain. More about it:
In my proposition we not have to change constructor every time after Object.create like it is in current best answer by #Jordão.
Solution also enables to create many abstract classes in hierarchy, we need only to create abstract property in prototype.

Another thing you might want to enforce is making sure your abstract class is not instantiated. You can do that by defining a function that acts as FLAG ones set as the Abstract class constructor. This will then try to construct the FLAG which will call its constructor containing exception to be thrown. Example below:
(function(){
var FLAG_ABSTRACT = function(__class){
throw "Error: Trying to instantiate an abstract class:"+__class
}
var Class = function (){
Class.prototype.constructor = new FLAG_ABSTRACT("Class");
}
//will throw exception
var foo = new Class();
})()

function Animal(type) {
if (type == "cat") {
this.__proto__ = Cat.prototype;
} else if (type == "dog") {
this.__proto__ = Dog.prototype;
} else if (type == "fish") {
this.__proto__ = Fish.prototype;
}
}
Animal.prototype.say = function() {
alert("This animal can't speak!");
}
function Cat() {
// init cat
}
Cat.prototype = new Animal();
Cat.prototype.say = function() {
alert("Meow!");
}
function Dog() {
// init dog
}
Dog.prototype = new Animal();
Dog.prototype.say = function() {
alert("Bark!");
}
function Fish() {
// init fish
}
Fish.prototype = new Animal();
var newAnimal = new Animal("dog");
newAnimal.say();
This isn't guaranteed to work as __proto__ isn't a standard variable, but it works at least in Firefox and Safari.
If you don't understand how it works, read about the prototype chain.

You can create abstract classes by using object prototypes, a simple example can be as follows :
var SampleInterface = {
addItem : function(item){}
}
You can change above method or not, it is up to you when you implement it. For a detailed observation, you may want to visit here.

Javascript can have inheritance, check out the URL below:
http://www.webreference.com/js/column79/
Andrew

We can use Factory design pattern in this case. Javascript use prototype to inherit the parent's members.
Define the parent class constructor.
var Animal = function() {
this.type = 'animal';
return this;
}
Animal.prototype.tired = function() {
console.log('sleeping: zzzZZZ ~');
}
And then create children class.
// These are the child classes
Animal.cat = function() {
this.type = 'cat';
this.says = function() {
console.log('says: meow');
}
}
Then define the children class constructor.
// Define the child class constructor -- Factory Design Pattern.
Animal.born = function(type) {
// Inherit all members and methods from parent class,
// and also keep its own members.
Animal[type].prototype = new Animal();
// Square bracket notation can deal with variable object.
creature = new Animal[type]();
return creature;
}
Test it.
var timmy = Animal.born('cat');
console.log(timmy.type) // cat
timmy.says(); // meow
timmy.tired(); // zzzZZZ~
Here's the Codepen link for the full example coding.

//Your Abstract class Animal
function Animal(type) {
this.say = type.say;
}
function catClass() {
this.say = function () {
console.log("I am a cat!")
}
}
function dogClass() {
this.say = function () {
console.log("I am a dog!")
}
}
var cat = new Animal(new catClass());
var dog = new Animal(new dogClass());
cat.say(); //I am a cat!
dog.say(); //I am a dog!

I think All Those answers specially first two (by some and jordão) answer the question clearly with conventional prototype base JavaScript concept.
Now as you want the animal class constructor to behave according to the passed parameter to the construction, I think this is very much similar to basic behavior of Creational Patterns for example Factory Pattern.
Here i made a little approach to make it work that way.
var Animal = function(type) {
this.type=type;
if(type=='dog')
{
return new Dog();
}
else if(type=="cat")
{
return new Cat();
}
};
Animal.prototype.whoAreYou=function()
{
console.log("I am a "+this.type);
}
Animal.prototype.say = function(){
console.log("Not implemented");
};
var Cat =function () {
Animal.call(this);
this.type="cat";
};
Cat.prototype=Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.say=function()
{
console.log("meow");
}
var Dog =function () {
Animal.call(this);
this.type="dog";
};
Dog.prototype=Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.say=function()
{
console.log("bark");
}
var animal=new Animal();
var dog = new Animal('dog');
var cat=new Animal('cat');
animal.whoAreYou(); //I am a undefined
animal.say(); //Not implemented
dog.whoAreYou(); //I am a dog
dog.say(); //bark
cat.whoAreYou(); //I am a cat
cat.say(); //meow

/****************************************/
/* version 1 */
/****************************************/
var Animal = function(params) {
this.say = function()
{
console.log(params);
}
};
var Cat = function() {
Animal.call(this, "moes");
};
var Dog = function() {
Animal.call(this, "vewa");
};
var cat = new Cat();
var dog = new Dog();
cat.say();
dog.say();
/****************************************/
/* version 2 */
/****************************************/
var Cat = function(params) {
this.say = function()
{
console.log(params);
}
};
var Dog = function(params) {
this.say = function()
{
console.log(params);
}
};
var Animal = function(type) {
var obj;
var factory = function()
{
switch(type)
{
case "cat":
obj = new Cat("bark");
break;
case "dog":
obj = new Dog("meow");
break;
}
}
var init = function()
{
factory();
return obj;
}
return init();
};
var cat = new Animal('cat');
var dog = new Animal('dog');
cat.say();
dog.say();

If you want to make sure that your base classes and their members are strictly abstract here is a base class that does this for you:
class AbstractBase{
constructor(){}
checkConstructor(c){
if(this.constructor!=c) return;
throw new Error(`Abstract class ${this.constructor.name} cannot be instantiated`);
}
throwAbstract(){
throw new Error(`${this.constructor.name} must implement abstract member`);}
}
class FooBase extends AbstractBase{
constructor(){
super();
this.checkConstructor(FooBase)}
doStuff(){this.throwAbstract();}
doOtherStuff(){this.throwAbstract();}
}
class FooBar extends FooBase{
constructor(){
super();}
doOtherStuff(){/*some code here*/;}
}
var fooBase = new FooBase(); //<- Error: Abstract class FooBase cannot be instantiated
var fooBar = new FooBar(); //<- OK
fooBar.doStuff(); //<- Error: FooBar must implement abstract member
fooBar.doOtherStuff(); //<- OK
Strict mode makes it impossible to log the caller in the throwAbstract method but the error should occur in a debug environment that would show the stack trace.

"use strict";
function Abstract (...arg){
// create abstract constructor
if( this.constructor.name === 'Object' || this.constructor === Abstract ) throw { ErrorType : "can't call abstract class with new !" , }
// ceate abstract method
Object.defineProperty( this , 'config' , {
value : function(){
console.log('config parent')
}
});
// or other
return this ;
};
class Home extends Abstract{
name = '';
constructor(...arg){
super(...arg) ;
}
config(){
// this method not working
console.log('config child')
}
}
let y = new Home( "home" , 'dasd');
y.config();

Related

Constructor property of an object

I came across this example while reading the prototype.
function Animal(){
this.name = 'Animal'
}
var animal1 = new Animal();
function Rabbit(){
this.canEat = true;
}
Rabbit.prototype = new Animal();
var r = new Rabbit();
console.log(r.constructor)
And the console is giving me Animal as the output for r.constructor, which is a little confusing as the constructor property should have returned Rabbit as r is created by invoking Rabbit with the new operator.
Also, if I invoke the Rabbit function before assigning the prototype it gives me the desired result.
Objects inherit constructor from their prototype (typically); they get their prototype from the prototype property of the constructor function that creates them when they're created (if they're created by a constructor function). Rabbit.prototype's constructor is incorrect, because of this:
Rabbit.prototype = new Animal();
That calls Animal to create a new instance, and assigns that instance as Rabbit.prototype. So its constructor, inherited from Animal.prototype, is Animal. You've replaced the default object that used to be on Rabbit.prototype (which had constructor set to Rabbit).
In general, that Rabbit.prototype = new Animal() is not the best way to set up inheritance. Instead, you do it like this:
Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;
and then in Rabbit:
function Rabbit() {
Animal.call(this); // ***
this.name = "Rabbit"; // Presumably we want to change Animal's deafult
this.canEat = true;
}
Three changes there:
We don't call Animal when setting up the inheritance, we just create a new object that uses Animal.prototype as its prototype, and put that on Rabbit.prototype.
We set constructor on the new object we've assigned to Rabbit.prototype.
We do call Animal when initializing the instance (in Rabbit).
Live Example:
function Animal(){
this.name = 'Animal'
}
var animal1 = new Animal();
function Rabbit() {
Animal.call(this); // ***
this.name = "Rabbit"; // Presumably we want to change Animal's deafult
this.canEat = true;
}
Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;
var r = new Rabbit();
console.log(r.constructor);
Or, of course, use ES2015+ class syntax, which handles this plumbing for you (along with a few other benefits).
class Animal {
constructor() {
this.name = "Animal";
}
}
class Rabbit extends Animal {
constructor() {
super();
this.name = "Rabbit";
this.canEat = true;
}
}
const r = new Rabbit();
console.log(r.constructor);

Javascript set base object when declare methods in prototype

I read that declaring object methods in prototype is good approach because it saves memory and allows to change implementation in any time for all objects.
But what i need to do when i need to set base object for object that uses prototype method declaration?
Example:
function Animal() {
this.age = 0;
this.weight = 0;
//other properties
}
Animal.prototype = {
//some methods for Animal
}
function Dog() {
//properties for Dog
}
Dog.prototype = {
//some methods for Dog
}
So, how can i set Animal as a base class(object) for Dog(because prototype property in Dog is implemented as custom object for methods)?
ES5 version (still most common, but I wouldn't recommend it - see ES6 version)
Based on this post here you need to use Object.create like this:
function Animal() {}
Animal.prototype = {};
function Dog() {}
Dog.prototype = Object.create( Animal.prototype );
Also see this solution with Object.assign (sadly IE doesn't support it)
ES6 version
class Animal {
// all your methods come in here. No more prototype needed.
}
class Dog extends Animal {
}
You can already use ES6 even though most browsers don't completely support it yet. Use babel to transpile you JS.
You could define Animal as a function and use its constructor to set an instance of it in the Dog prototype :
Dog.prototype = new Animal();
More complete code :
var Animal = function () {
this.age = 0;
this.weight = 0;
this.age = function () {
return this.age;
}
// define other methods ...
// ...
return this;
};
var Dog = function () {
// overriding the age
this.age= 10;
// define or override methods ...
// ...
return this;
};
// Dog extends animal
Dog.prototype = new Animal();
// Creating an instance of Dog.
var dog = new Dog();

How to set the constructor of an Object without changing to a new Object?

In this related question, the answer for setting a constructor is like so:
function OldClass() {
alert("old class with incomplete constructor")
}
function ChangedClass(){
alert('new class with same prototype and more complete constructor');
}
ChangedClass.prototype = OldClass.prototype;
var theClassIWant = new ChangedClass();
This is not really setting the constructor, it's making a new object and inheriting the prototype. How can I set the constructor of an Object without changing to a new Object? Is it possible?
P.S. I want something like this:
//non working code
var Foo = function() {}
Foo.prototype.constructor = function(bar_val) {
this.bar = bar_val;
}
var fez = new Foo("cat")
console.log(fez.bar); // outputs: cat;
constructor is a property of the constructor function's prototype, which points to the function itself by default.
When you modify Foo.prototype.constructor, this property points to another function. However, the constructor function Foo remains. So when you create an object, you are still instantiate the constructor function Foo, not the one Foo.prototype.constructor points to.
This is why your code doesn't work. Then let's talk why we need to change the constructor and how to.
In ES5 and before, we take advantage of prototype to simulate a class inheritance mechanism. Which looks like this:
// parent class
function Person(name) {
this.name = name
}
// define parent method
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent properties
this.job = 'Coding'
this.major = major
}
// inherits properties and methods from parent prototype
Coder.prototype = new Person()
// define child method
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
// instantiate a child object
var me = new Coder('Leo', 'JavaScript')
console.log(me) // {name: "Leo", job: "Coding", major: "JavaScript"}
Everything looks perfect, but there a problem:
console.log(me.constructor) // Person
What? Isn't me constructed with Coder? Why?
Go back to the first line of this answer, read it again: constructor is a property of the constructor function's prototype.
Originally Coder.prototype.constructor is Coder itself. But with this line: Coder.prototype = new Person(), it got changed. Coder.prototype.constructor now equals Person.prototype.constructor, which is Person.
Well, some would say, try instanceof. Yes, that works:
me instanceof Coder // true
But it's also true for Person, because Coder is a sub class of it:
me instanceof Person // true
This doesn't make sense so we need to fix the constructor problem. That's why we use Coder.prototype.constructor = Coder after Coder.prototype = new Person(), to get back the original constructor.
Full code looks like this:
// parent class
function Person(name) {
this.name = name
}
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent class
this.job = 'Coding'
this.major = major
}
Coder.prototype = new Person() // inherits parent's prototype
Coder.prototype.constructor = Coder // get back constructor
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
myClass = {
constructor: function(text){
console.log(text);
}
}
let ob = Object.create(myClass);
ob.constructor("old constructor "); //Output: old constructor
myClass.constructor = function(){
console.log("new constructor ")
}
ob.constructor(); //Output: new constructor
You can do this with every property or function of a class.
Watch this Video here. It explains it perfectly.

Object.create vs new

The following code works when I create my object with the constructor but when I do object.Create it doesn't get initialized properly. functionName is not a function. I have two questions. Why isn't the object.create working ?
How would I organize my code within the same Calculator Function so I could use both new and object.create ?
I know I can add the methods to Calculator.prototype and do Object.create but I was wondering if my code can be changed within the current structure to allow for both ?
//var calc = new Calculator();
var calc = Object.create(Calculator);
function Calculator(){
this.array = [];
this.results = 0;
this.calculate = function(){
try{
results = eval(this.array.join(''));
this.array = [results];
return results;
}
catch(error){
alert('Wrong arguments provided');
return this.array.join('');
}
},
this.isNumber = function(str){
return !isNaN(parseFloat(str)) && isFinite(str);
},
this.addToOperationsArray = function(str){
if (this.array.length <= 0 && !this.isNumber(str)){ // Don't add operand before any number.
return;
}
this.array.push(str);
},
this.clearEverything = function(){
this.array = [];
}
}
There is no constructor invocation with Object.create.
You can get similar results in a multitude of ways. See if something along these lines helps you:
function Calculator() {
this.array = [];
this.results = 0;
}
Calculator.prototype = {
calculate: function() {
try {
results = eval(this.array.join(''));
this.array = [results];
return results;
} catch (error) {
alert('Wrong arguments provided');
return this.array.join('');
}
},
isNumber: function(str) {
return !isNaN(parseFloat(str)) && isFinite(str);
},
addToOperationsArray: function(str) {
if (this.array.length <= 0 && !this.isNumber(str)) { // Don't add operand before any number.
return;
}
this.array.push(str);
},
clearEverything: function() {
this.array = [];
}
};
// create using 'new'
var calc1 = new Calculator();
// create using 'Object.create'
// the constructor function is not called
// but properties of returned object can be passed to the function, and
// you can control the enumerable, writable, configurable properties
var calc2 = Object.create(Calculator.prototype, {
'array': {
value: [],
enumerable: true
},
'results': {
value: 0,
enumerable: true
}
});
// create using 'Object.create'
// and invoke the constructor with 'call',
// explicitly setting 'this'
var calc3 = Object.create(Calculator.prototype);
Calculator.call(calc3);
console.log(calc1); // Calculator {array: Array[0], results: 0}
console.log(calc2); // Object {array: Array[0], results: 0}
console.log(calc3); // Object {array: Array[0], results: 0}
Object.create() //This for inherit the parent object
what you want is to instantiate the object, you can do it like this:
var calc = new Calculator() //This will inherit it's prototype and execute the constructor for you.
Object.create works with new side by side not against. Just to make it more clear about prototype inheritance and instantiate, let's take step back, I'll provide you with example:
// CREATE || Object.create for inheritence by prototyping
var Thing = function (name) {
this.type = "universal";
this.name = name;
}
Thing.prototype = {
say: function(something) {
console.log(this.name + " say something " + something);
},
check_soul: function (){
console.log(this.name + " soul is " + this.type);
}
}
// constructor for God
var God = function(name){
Thing.call(this, name); // Execute parent constructor also with current context
this.type = "pure"; // overwrite the type
}
God.prototype = Object.create(Thing.prototype); // inherit God from Thing
God.prototype.constructor = God; // implement the constructor
// constructor for Demon
var Demon = function(name){
Thing.call(this, name);
this.type = "corrupted";
}
Demon.prototype = Object.create(Thing.prototype, {
say: {
value: function(something){ // Overwrite Thing prototype for say
console.info(this.name + " say: Let's destory " + something + "!");
}}
}); // inherit Demon from Thing
Demon.prototype.constructor = Demon;
/////////////////////////////////////////////////////////////////////////////////////
// NEW || new for instantiation
var anonymous = new Thing("Anonymous");
anonymous.check_soul();
var god = new God("Zeus");
god.check_soul();
god.say("omni");
var demon = new Demon("Lucifer");
demon.check_soul();
demon.say("human");
Example above is too verbose? (ES2015 here to help) note that this can only apply on node v6 and above.
// CREATE || Object.create for inheritence by prototyping
'use strict';
class Thing {
constructor (name){
this.type = "universal";
this.name = name;
}
say(something) {
console.log(this.name + " say something " + something);
}
check_soul() {
console.log(this.name + " soul is " + this.type);
}
}
class God extends Thing { // inherit God from Thing and implement the constructor
constructor (name){
super(name); // Execute parent constructor also with current context
this.type = "pure"; // overwrite the type
}
}
class Demon extends Thing { // inherit Demon from Thing and implement the constructor
constructor (name){
super(name); // Execute parent constructor also with current context
this.type = "corrupted"; // overwrite the type
}
say(something) { // Overwrite Thing prototype for say
console.info(this.name + " say: Let's destory " + something + "!");
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NEW || new for instantiation
var anonymous = new Thing("Anonymous");
anonymous.check_soul();
var god = new God("Zeus");
god.check_soul();
god.say("omni");
var demon = new Demon("Lucifer");
demon.check_soul();
demon.say("human");
a little bit late, may be you have noticed, but in your implementation theres is at least one side effect in the code Calculator.prototype.constructor this will point to Object.prototype.constructor instead of the Calculator constructor, what are you doing is overwriting every property of the prototype chain, it is best practice to use dot notation to add new properties Calculator.prototype.method = () => { // some code }

Purpose of property copying to inheriting type

While playing around with the online TypeScript compiler, I've noticed that the creators chose to implement inheritance with the help of the following method (which I have made somewhat more readable):
var __extends = function(type, base) {
for (var prop in base) { // why copy the properties?
if (base.hasOwnProperty(prop)) {
type[prop] = base[prop];
}
}
function __() { // <- ?
this.constructor = type;
}
__.prototype = base.prototype.
type.prototype = new __();
};
The method is then used in the following manner:
var Item = (function () {
function Item() {
}
return Item;
})();
var Sword = (function (base) {
__extends (Sword, base);
function Sword() {
base.call(this);
}
return Sword;
})(Item);
I have a hard time understandind the implementation of the __extends method.
What is the purpose of manually copying all the properties from the extending type? Won't inheriting the prototype take care of that?
Is there a performance penalty when searching for properties in the prototype tree as opposed to directly copied properties?
The second part I also can't understand the purpose of. Instead of doing this:
function __() {
this.constructor = type;
}
__.prototype = base.prototype.
type.prototype = new __();
Couldn't this simply be implemented as:
type.prototype = base.prototype;
Great question. Let's break this down.
var __extends = function(type, base) {
// ** Begin static-side inheritance **
for (var prop in base) {
if (base.hasOwnProperty(prop)) {
type[prop] = base[prop];
}
}
// ** End static-side inheritance **
// ** Begin Object.create polyfill **
function __() { // <- ?
this.constructor = type;
}
__.prototype = base.prototype.
// ** End Object.create polyfill **
// ** Prototype setup **
type.prototype = new __();
};
First up is the static-side inheritance. TypeScript's type system enforces that if some type has a static method, a derived class also has that method (or a method whose signature is a subtype of the base class method). This is useful for things like factory patterns, e.g.:
class Car {
static create(name: string, topSpeed: number): Car {
// ...
return new this(/* ... */);
}
}
class RaceCar extends Car {
// RaceCar ignores topSpeed because it goes super fast
static create(name: string): RaceCar {
// ...
return new this(/* ... */);
}
}
class Truck extends Car {
}
function makeTestCar(t: typeof Car) {
return t.create('test', 60);
}
var car = makeTestCar(Car); // returns an instance of Car
var raceCar = makeTestCar(RaceCar); // returns an instance of RaceCar
var truck = makeTestCar(Truck); // OK, even though Truck doesn't explicitly implement 'create'
Note that in the last line, the Truck class got its create method via its base class Car. The copying is needed because Truck.__proto__ is not Car.
Next up we have the Object.create polyfill. It's not sufficient to write type.prototype = base.prototype because the __proto__ (AKA [[proto]]) and prototype members are not the same thing. Other answers on SO have given a better rundown of prototypal inheritance so I'll defer to those.
Finally the last line sets up the prototype of the constructor so that the created object has the correct __proto__
Extends copies prototype and static members (shallow copy). Statics are Parent.things and prototypes are Parent.prototype.things The way the prototype.things are copied is how the poly fill for Object create works.
var __extends = this.__extends || function (d, b) {
//Copies Item.things to Sword.things
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
//Copies Item.prototype.things to Sword.prototype.things
//this is a polyfill for Object.create
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Sword = (function (_super) {
__extends(Sword, _super);
function Sword() {
_super.apply(this, arguments);
}
return Sword;
})(Iten);
Consider the following Typescript:
class Item {
public static DAMAGE = 0;
};
In JavaScript this will be:
var Item = (function () {
function Item() {
}
Item.DAMAGE = 0;
return Item;
})();
How would I use static DAMAGE? See the following example (simplefied JS);
//Using static to make general getters and setters
var Item = function(damage){
this._data = [];
this.set(Item.DAMAGE,damage)
};
Item.DAMAGE=0;
Item.prototype.get=function(dataIndex){
return this._data[dataIndex];
};
Item.prototype.set=function(dataIndex,val){
//maybe execute Item.rules[dataIndex].set(val) for validating value
this._data[dataIndex] = val;
return val;
};
var i = new Item(22);
//I could get damage using i.get(0)
//but the following reads more easily
i.get(Itesm.DAMAGE);
Introduction about constructor functions, prototype, inheritance, mix ins and the this value here: https://stackoverflow.com/a/16063711/1641941

Categories