I need different constructors for my instances. What is a common pattern for that?
-
be a bit more specific please. you want constructors with different parameter sets? – gblazex Jul 10 '10 at 20:25
-
Can you have more than one constructor in Javascript? – Doug Hauf Jul 06 '14 at 23:30
-
Yes and no @DougHauf. Yes because the answer provided by bobince provides a way to deliver equivalent behaviour. No because if you wanted multiple distinct constructor functions (each sharing the same prototype object) how would the constructor property of the prototype object get set (since the constructor property can only point to one constructor function). – Moika Turns Apr 24 '17 at 09:26
-
4**All of these answers are old/not-ideal.** I'm too lazy to type up an answer, but you can pass an object around to functions and constructors and then use the keys just like you would arguments, e.g.: `function ({ oneThing = 7, otherThing = defaultValue } = {}) { }`. The extra `= {}` I put in there is another trick I learned recently, in case you want the possibility of the user passing no object in at all and using all of the defaults. – Andrew Jan 08 '20 at 19:14
-
2Followup: Here are some good ways to solve this problem: https://stackoverflow.com/a/32626901/1599699 https://stackoverflow.com/a/41051984/1599699 https://stackoverflow.com/a/48287734/1599699 I'm especially fond of the last one for true multiple-constructor-like support, using static factory functions as constructors (`return new this();`, `return new this.otherStaticFactoryFunction();`, etc.)! – Andrew Mar 31 '20 at 17:58
13 Answers
JavaScript doesn't have function overloading, including for methods or constructors.
If you want a function to behave differently depending on the number and types of parameters you pass to it, you'll have to sniff them manually. JavaScript will happily call a function with more or fewer than the declared number of arguments.
function foo(a, b) {
if (b===undefined) // parameter was omitted in call
b= 'some default value';
if (typeof(a)==='string')
this._constructInSomeWay(a, b);
else if (a instanceof MyType)
this._constructInSomeOtherWay(a, b);
}
You can also access arguments
as an array-like to get any further arguments passed in.
If you need more complex arguments, it can be a good idea to put some or all of them inside an object lookup:
function bar(argmap) {
if ('optionalparam' in argmap)
this._constructInSomeWay(argmap.param, argmap.optionalparam);
...
}
bar({param: 1, optionalparam: 2})
Python demonstrates how default and named arguments can be used to cover the most use cases in a more practical and graceful way than function overloading. JavaScript, not so much.

- 528,062
- 107
- 651
- 834
-
2Thanks, this is really nice. I would say the second option is useful not just when you have complex arguments, but also simple-yet-hard-to-distinguish arguments, e.g. supporting `MyObj({foo: "foo"})` plus `MyObj({bar: "bar"})`. MyObj has two constructors - but both take one argument, which is a string :-) – Alex Dean Nov 15 '12 at 11:06
-
1
-
Hi @DougHauf, Crockford's book 'JavaScript: The Good Parts' has a section on this named 'Object Specifiers', plenty of examples refer to it online. – Moika Turns Apr 24 '17 at 09:42
-
"JavaScript will happily call a function with more or fewer than the declared number of arguments" this needs HAHA emoji, HAHAscript :D :D, I think SO should add emoji reactions to answers and questions. – Amr Lotfy Jan 10 '21 at 02:11
you can use class with static methods that return an instance of that class
class MyClass {
constructor(a,b,c,d){
this.a = a
this.b = b
this.c = c
this.d = d
}
static BAndCInstance(b,c){
return new MyClass(null,b,c)
}
static BAndDInstance(b,d){
return new MyClass(null,b, null,d)
}
}
//new Instance just with a and other is nul this can
//use for other params that are first in constructor
const myclass=new MyClass(a)
//an Instance that has b and c params
const instanceWithBAndC = MyClass.BAndCInstance(b,c)
//another example for b and d
const instanceWithBAndD = MyClass.BAndDInstance(b,d)
with this pattern you can create multi constructor

- 1,882
- 10
- 19
-
12This is the best answer. The others resort to parsing arrays and doing a bunch of unnecessary work. – Blane Townsend Aug 13 '19 at 14:56
How do you find this one?
function Foobar(foobar) {
this.foobar = foobar;
}
Foobar.prototype = {
foobar: null
};
Foobar.fromComponents = function(foo, bar) {
var foobar = foo + bar;
return new Foobar(foobar);
};
//usage: the following two lines give the same result
var x = Foobar.fromComponents('Abc', 'Cde');
var y = new Foobar('AbcDef')
-
3return new this(foobar); doesn't work. I change on return new Foobar(foobar); and all is work correct. – isxaker Oct 24 '13 at 07:10
-
11I don't get it. Can you add the code where you are actually using it? Are you going to have to call fromComponents every time? Because that's not truly a constructor, but rather a helper function. @bobince's answer seems more accurate then. – hofnarwillie Jul 03 '14 at 08:33
-
1@hofnarwillie While not quite an exact constructor, by using a static method it performs fairly similar ie var foobarObj = Foobar.fromComponents(foo,bar); is all you need to create a new object with the alternative arguments. – Nathan Williams Jan 19 '17 at 02:09
-
what if Foobaz extends from Foobar, wouldn't Foobaz.fromComponets create Foobar instances? – Capi Etheriel Jan 26 '22 at 14:15
Didn't feel like doing it by hand as in bobince's answer, so I just completely ripped off jQuery's plugin options pattern.
Here's the constructor:
//default constructor for Preset 'class'
function Preset(params) {
var properties = $.extend({
//these are the defaults
id: null,
name: null,
inItems: [],
outItems: [],
}, params);
console.log('Preset instantiated');
this.id = properties.id;
this.name = properties.name;
this.inItems = properties.inItems;
this.outItems = properties.outItems;
}
Here's different ways of instantiation:
presetNoParams = new Preset();
presetEmptyParams = new Preset({});
presetSomeParams = new Preset({id: 666, inItems:['item_1', 'item_2']});
presetAllParams = new Preset({id: 666, name: 'SOpreset', inItems: ['item_1', 'item_2'], outItems: ['item_3', 'item_4']});
And here's what that made:
presetNoParams
Preset {id: null, name: null, inItems: Array[0], outItems: Array[0]}
presetEmptyParams
Preset {id: null, name: null, inItems: Array[0], outItems: Array[0]}
presetSomeParams
Preset {id: 666, name: null, inItems: Array[2], outItems: Array[0]}
presetAllParams
Preset {id: 666, name: "SOpreset", inItems: Array[2], outItems: Array[2]}

- 2,776
- 1
- 19
- 20
-
I've rolled the same pattern in node.js too now with: https://www.npmjs.com/package/extend – Jacob McKay Jun 17 '16 at 16:37
Answering because this question is returned first in google but the answers are now outdated.
You can use Destructuring objects as constructor parameters in ES6
Here's the pattern:
You can't have multiple constructors, but you can use destructuring and default values to do what you want.
export class myClass {
constructor({ myArray = [1, 2, 3], myString = 'Hello World' }) {
// ..
}
}
And you can do this if you want to support a 'parameterless' constructor.
export class myClass {
constructor({myArray = [1, 2, 3], myString = 'Hello World'} = {}) {
// ..
}
}

- 10,673
- 3
- 42
- 55
Going further with eruciform's answer, you can chain your new
call into your init
method.
function Foo () {
this.bar = 'baz';
}
Foo.prototype.init_1 = function (bar) {
this.bar = bar;
return this;
};
Foo.prototype.init_2 = function (baz) {
this.bar = 'something to do with '+baz;
return this;
};
var a = new Foo().init_1('constructor 1');
var b = new Foo().init_2('constructor 2');

- 450
- 5
- 11
-
So basically what you are doing here is taking the object Foo and then calling the init_1 and init_2 parameters with the prototype functions. Should your init_1 and init_2 have the word function with them. – Doug Hauf Jul 06 '14 at 23:38
-
-
-
Are you sure this works? I wasn't able to chain `new Foo()` and the call to `init` together because I wasn't able to access properties on the objects. I had to run `var a = new Foo(); a.init_1('constructor 1');` – Millie Smith Feb 07 '17 at 05:37
-
@MillieSmith I'll admit I haven't written JS in a while now... but I just pasted this code into the Chrome JS console and the chain from new to init worked. – laughingbovine Feb 13 '17 at 15:27
-
what's the benefit of putting these two init functions on the prototype chain instead of putting it directly in the Foo function? – Jacques Feb 16 '18 at 07:32
export default class Order {
static fromCart(cart) {
var newOrder = new Order();
newOrder.items = cart.items;
newOrder.sum = cart.sum;
return newOrder;
}
static fromOrder(id, order) {
var newOrder = new Order();
newOrder.id = id;
newOrder.items = order.items;
newOrder.sum = order.sum;
return newOrder;
}
}
Useges:
var newOrder = Order.fromCart(cart)
var newOrder = Order.fromOrder(id, oldOrder)

- 431
- 7
- 13
Sometimes, default values for parameters is enough for multiple constructors. And when that doesn't suffice, I try to wrap most of the constructor functionality into an init(other-params) function that is called afterwards. Also consider using the factory concept to make an object that can effectively create the other objects you want.
http://en.wikipedia.org/w/index.php?title=Factory_method_pattern&oldid=363482142#Javascript

- 7,680
- 1
- 35
- 47
-
1Factory method feels like a good solution - just be sure to not confuse it with the use of a separate factory class, which probably is completely irrelevant in this use case. – Simon Groenewolt Jul 10 '10 at 21:37
-
1
In general you can pass more parameters, and when you instance the object you can also miss some value, and their default value will be undefined, if you don't want mange undefined, the easy way to build multi constructor should be in this way:
class Car {
constructor(brand, year = '', owner = '') { // assign default value
this.carname = brand;
this.year = year;
this.owner = owner;
}
presentCarName() {
return 'I have a ' + this.carname;
}
presentCarNameAndYear() {
return 'I have a ' + this.carname + ' year: ' + this.year;
}
}
let myCar = new Car("Ford");
console.log(myCar.presentCarName());
myCar = new Car("Ford", 1996);
console.log(myCar.presentCarNameAndYear());

- 76
- 1
- 5
this is my solution, simply use methods
and return this
e.g.
class Person{
name;
age;
gender;
cash;
constructor() {
}
init(name, age, gender, cash){
this.name = name;
this.age = age;
this.gender = gender;
this.cash = cash;
return this;
}
initCyborg(name, age){
this.name = name + ' Reborn';
this.age = age + 5;
this.cash = 999999;
this.gender = "cyborg";
return this;
}
initMale(name, age, salariesOf2000Received){
this.name = name;
this.age = age;
this.gender = "male";
this.cash = 2000 * salariesOf2000Received;
return this;
}
}
then
var john = new Person().init("John Doe", 30, "male", 2000);
var cyborg = new Person().initCyborg("Terminator-6000", 3000);
var rickAstley = new Person().initMale("Rick Astley", 56, 2);
console.log(john);
console.log(cyborg);
console.log(rickAstley);

- 5,187
- 1
- 21
- 32
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.

- 131
- 2
- 5
This is the example given for multiple constructors in Programming in HTML5 with JavaScript and CSS3 - Exam Ref.
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"));

- 353
- 3
- 10
-
And Immutability? using prototype puts properties public, right? – Gabriel Simas Jun 15 '17 at 22:29
-
7That is incorrect. Your second constructor definition overrides the first one, so when you're calling new Book() later on, you're calling the second constructor with all parameters' values set to undefined. – ErroneousFatality Apr 26 '18 at 16:40
12 years down the lane now you can use Js class
& static
method just like this
class Human {
static Person1(){
let o = new Human();
o.name = "Person1";
return o;
}
static Person2(){
let o = new Human();
o.name = "Person2";
return o;
}
sayhello(){
alert(`Hello ${this.name}`);
}
}
So in the code above I have defined a class
with two static
and one instance method
. Now since it's static
it can be called without any instance object so we can call create two person like
var p1 = Human.Person1();
var p2 = Human.Person2();
and can call in the instance method
p1.sayhello();
p2.sayhello();
that will return
Hello Person1
Hello Person2
I have even tested in console

- 3,644
- 1
- 27
- 40
-
This answer is voted down with no comments and I am not able to understand why ? Can someone plz make me understand what is wrong here. – Vinod Srivastav Feb 10 '23 at 13:24