Reputation: 6516
In ES5 it was possible to create multiple constructors for a class while keeping common parts to both using prototypes, as shown below
function Book() {
//just creates an empty book.
}
function Book(title, length, author) {
this.title = title;
this.Length = length;
this.author = author;
}
Book.prototype = {
ISBN: "",
Length: -1,
genre: "",
covering: "",
author: "",
currentPage: 0,
title: "",
flipTo: function FlipToAPage(pNum) {
this.currentPage = pNum;
},
turnPageForward: function turnForward() {
this.flipTo(this.currentPage++);
},
turnPageBackward: function turnBackward() {
this.flipTo(this.currentPage--);
}
};
var books = new Array(new Book(), new Book("First Edition", 350, "Random"));
I want to achieve the same result using ES6 class and constructor syntax
class Book{
constructore (){}
}
Upvotes: 6
Views: 8312
Reputation: 161
I believe there are two answers. One using 'pure' Javascript with IIFE function to hide its auxiliary construction functions. And the other using a NodeJS module to also hide its auxiliary construction functions.
I will show only the example with a NodeJS module.
Class Vector2d.js:
/*
Implement a class of type Vetor2d with three types of constructors.
*/
// If a constructor function is successfully executed,
// must have its value changed to 'true'.let global_wasExecuted = false;
global_wasExecuted = false;
//Tests whether number_value is a numeric type
function isNumber(number_value) {
let hasError = !(typeof number_value === 'number') || !isFinite(number_value);
if (hasError === false){
hasError = isNaN(number_value);
}
return !hasError;
}
// Object with 'x' and 'y' properties associated with its values.
function vector(x,y){
return {'x': x, 'y': y};
}
//constructor in case x and y are 'undefined'
function new_vector_zero(x, y){
if (x === undefined && y === undefined){
global_wasExecuted = true;
return new vector(0,0);
}
}
//constructor in case x and y are numbers
function new_vector_numbers(x, y){
let x_isNumber = isNumber(x);
let y_isNumber = isNumber(y);
if (x_isNumber && y_isNumber){
global_wasExecuted = true;
return new vector(x,y);
}
}
//constructor in case x is an object and y is any
//thing (he is ignored!)
function new_vector_object(x, y){
let x_ehObject = typeof x === 'object';
//ignore y type
if (x_ehObject){
//assigns the object only for clarity of code
let x_object = x;
//tests whether x_object has the properties 'x' and 'y'
if ('x' in x_object && 'y' in x_object){
global_wasExecuted = true;
/*
we only know that x_object has the properties 'x' and 'y',
now we will test if the property values are valid,
calling the class constructor again.
*/
return new Vector2d(x_object.x, x_object.y);
}
}
}
//Function that returns an array of constructor functions
function constructors(){
let c = [];
c.push(new_vector_zero);
c.push(new_vector_numbers);
c.push(new_vector_object);
/*
Your imagination is the limit!
Create as many construction functions as you want.
*/
return c;
}
class Vector2d {
constructor(x, y){
//returns an array of constructor functions
let my_constructors = constructors();
global_wasExecuted = false;
//variable for the return of the 'vector' function
let new_vector;
//traverses the array executing its corresponding constructor function
for (let index = 0; index < my_constructors.length; index++) {
//execute a function added by the 'constructors' function
new_vector = my_constructors[index](x,y);
if (global_wasExecuted) {
this.x = new_vector.x;
this.y = new_vector.y;
break;
};
};
}
toString(){
return `(x: ${this.x}, y: ${this.y})`;
}
}
//Only the 'Vector2d' class will be visible externally
module.exports = Vector2d;
The useVector2d.js file uses the Vector2d.js module:
const Vector = require('./Vector2d');
let v1 = new Vector({x: 2, y: 3});
console.log(`v1 = ${v1.toString()}`);
let v2 = new Vector(1, 5.2);
console.log(`v2 = ${v2.toString()}`);
let v3 = new Vector();
console.log(`v3 = ${v3.toString()}`);
Terminal output:
v1 = (x: 2, y: 3)
v2 = (x: 1, y: 5.2)
v3 = (x: 0, y: 0)
With this we avoid dirty code (many if's and switch's spread throughout the code), difficult to maintain and test. Each building function knows which conditions to test. Increasing and / or decreasing your building functions is now simple.
Upvotes: 1
Reputation: 130
You can also get around this limitation by using ES6 classes with extends.
class Base{
Foo;
Bar;
}
class TypeA extends Base {
constructor(value) {
this.Foo = value;
}
}
class TypeB extends Base {
constructor(value) {
this.Bar = value;
}
}
Upvotes: 2
Reputation: 74204
Actually, it is indeed possible to create multiple constructors for one prototype. You just have to see that the constructor
property of the prototype is not special. Therefore, you can create multiple constructors as follows:
const type = (prototype, constructor) =>
(constructor.prototype = prototype, constructor);
const book = {
flipTo(page) {
this.page = page;
},
turnPageForward() {
this.page++;
},
turnPageBackward() {
this.page--;
}
};
const EmptyBook = type(book, function EmptyBook() {
this.constructor = EmptyBook;
this.ISBN = "";
this.title = "";
this.author = "";
this.genre = "";
this.covering = "";
this.length = -1;
this.page = 0;
});
const Book = type(book, function Book(title, author, length) {
this.constructor = Book;
this.ISBN = "";
this.title = title;
this.author = author;
this.genre = "";
this.covering = "";
this.length = length;
this.page = 0;
});
Just give the constructors different names. Hope that helps.
Upvotes: 0
Reputation: 1497
Function/constructor overloading is not supported in ECMAScript. You can use the arguments object to do so if you want to still hack it.
constructor(title, length, author) {
if(!arguments.length) {
// empty book
}
else {
this.title = title;
this.Length = length;
this.author = author;
}
}
Upvotes: 11