A constructor is a special method of a class or structure in object-oriented programming that initializes a newly created object of that type. Whenever an object is created, the constructor is called automatically.
A constructor is like an instance method that usually has the same name as the class, and can be used to set the values of the members of an object, either to default or to user-defined values. However, although it resembles it, a constructor is not a proper method since it doesn’t have a return type. Instead of performing a task by executing code, the constructor initializes the object, and it cannot be static, final, abstract, and synchronized.
Advertisement
Techopedia Explains Constructor
Constructors are not called explicitly and are invoked only once during their lifetime. In the case of a hierarchy of classes where a derived class inherits from a parent class, the execution sequence of the constructor is a call to the constructor of the parent class first and then that of the derived class. Constructors cannot be inherited.
Users do not need to write constructors for every class. A constructor can be declared using any of the access modifiers. It is mandatory to have a constructor with the right access modifier.
However, the compiler supplies a default if an access modifier is not defined in the class and a constructor is not declared. This default constructor cannot be found inside the source code since it’s found in the .class file. Its behavior depends on the language.
Although it’s often mistaken for a default constructor, in Java constructors with no arguments also exist and are called “no-arg constructors.” While they share the signature with the default constructor, the body of no-arg constructors isn’t empty and they can have any code. Constructors with arguments, instead, are known as “parameterized constructors.”
If a constructor is declared as private, the class cannot be created or derived and hence cannot be instantiated. Such a constructor, however, can be overloaded with different sets of parameters.
The following is recommended in constructor design:
Logic involving specific operations that need to be executed at a particular event in an application - such as opening a database connection - should not be written in a constructor.
When using derived class constructors, the parent class constructor should be passed the correct parameters.
Better code maintainability comes from having the initialization and other related logic in one main constructor and cross-calling this constructor from other overloaded constructors.
Because a constructor cannot return a value to the calling code, it is a good practice to throw an exception when a failure is encountered.
Constructor chaining occurs whenever a base class is extended by a child. The parent class is, therefore, invoked first every time an object of that child class is created.
The
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
2 method is a special method of a class for creating and initializing an object instance of that class.Note: This page introduces the
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
2 syntax. For the class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
2 property present on all objects, see class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
5.constructor[] { /* … */ }
constructor[argument0] { /* … */ }
constructor[argument0, argument1] { /* … */ }
constructor[argument0, argument1, /* … ,*/ argumentN] { /* … */ }
A constructor enables you to provide any custom initialization that must be done before any other methods can be called on an instantiated object.
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
If you don't provide your own constructor, then a default constructor will be supplied for you. If your class is a base class, the default constructor is empty:
constructor[] {}
If your class is a derived class, the default constructor calls the parent constructor, passing along any arguments that were provided:
constructor[...args] {
super[...args];
}
Note: The difference between an explicit constructor like the one above and the default constructor is that the latter doesn't actually invoke the array iterator through argument spreading.
That enables code like this to work:
class ValidationError extends Error {
printCustomerMessage[] {
return `Validation failed :-[ [details: ${this.message}]`;
}
}
try {
throw new ValidationError["Not a valid phone number"];
} catch [error] {
if [error instanceof ValidationError] {
console.log[error.name]; // This is Error instead of ValidationError!
console.log[error.printCustomerMessage[]];
} else {
console.log["Unknown error", error];
throw error;
}
}
The
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
6 class doesn't need an explicit constructor, because it doesn't need to do any custom initialization. The default constructor then takes care of initializing the parent class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
7 from the argument it is given.However, if you provide your own constructor, and your class derives from some parent class, then you must explicitly call the parent class constructor using
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
8. For example:class ValidationError extends Error {
constructor[message] {
super[message]; // call parent class constructor
this.name = "ValidationError";
this.code = "42";
}
printCustomerMessage[] {
return `Validation failed :-[ [details: ${this.message}, code: ${this.code}]`;
}
}
try {
throw new ValidationError["Not a valid phone number"];
} catch [error] {
if [error instanceof ValidationError] {
console.log[error.name]; // Now this is ValidationError!
console.log[error.printCustomerMessage[]];
} else {
console.log["Unknown error", error];
throw error;
}
}
Using
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
9 on a class goes through the following steps:- [If it's a derived class] The
2 body before theclass Person { constructor[name] { this.name = name; } introduce[] { console.log[`Hello, my name is ${this.name}`]; } } const otto = new Person["Otto"]; otto.introduce[]; // Hello, my name is Otto
8 call is evaluated. This part should not accessclass Person { constructor[name] { this.name = name; } introduce[] { console.log[`Hello, my name is ${this.name}`]; } } const otto = new Person["Otto"]; otto.introduce[]; // Hello, my name is Otto
2 because it's not yet initialized.constructor[] {}
- [If it's a derived class] The
8 call is evaluated, which initializes the parent class through the same process.class Person { constructor[name] { this.name = name; } introduce[] { console.log[`Hello, my name is ${this.name}`]; } } const otto = new Person["Otto"]; otto.introduce[]; // Hello, my name is Otto
- The current class's fields are initialized.
- The
2 body after theclass Person { constructor[name] { this.name = name; } introduce[] { console.log[`Hello, my name is ${this.name}`]; } } const otto = new Person["Otto"]; otto.introduce[]; // Hello, my name is Otto
8 call [or the entire body, if it's a base class] is evaluated.class Person { constructor[name] { this.name = name; } introduce[] { console.log[`Hello, my name is ${this.name}`]; } } const otto = new Person["Otto"]; otto.introduce[]; // Hello, my name is Otto
Within the
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
2 body, you can access the object being created through constructor[] {}
2 and access the class that is called with class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
9 through constructor[] {}
9. Note that methods [including getters and setters] and the prototype chain are already initialized on constructor[] {}
2 before the class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
2 is executed, so you can even access methods of the subclass from the constructor of the superclass. However, if those methods use constructor[] {}
2, the constructor[] {}
2 will not have been fully initialized yet. This means reading public fields of the derived class will result in constructor[...args] {
super[...args];
}
4, while reading private fields will result in a constructor[...args] {
super[...args];
}
5.new [class C extends class B {
constructor[] {
console.log[this.foo[]];
}
} {
#a = 1;
foo[] {
return this.#a; // TypeError: Cannot read private member #a from an object whose class did not declare it
// It's not really because the class didn't declare it,
// but because the private field isn't initialized yet
// when the superclass constructor is running
}
}][];
The
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
2 method may have a return value. While the base class may return anything from its constructor, the derived class must return an object or constructor[...args] {
super[...args];
}
4, or a constructor[...args] {
super[...args];
}
5 will be thrown.class ParentClass {
constructor[] {
return 1;
}
}
console.log[new ParentClass[]]; // ParentClass {}
// The return value is ignored because it's not an object
// This is consistent with function constructors
class ChildClass extends ParentClass {
constructor[] {
return 1;
}
}
console.log[new ChildClass[]]; // TypeError: Derived constructors may only return object or undefined
If the parent class constructor returns an object, that object will be used as the
constructor[] {}
2 value on which class fields of the derived class will be defined. This trick is called , which allows a derived class's fields [including private ones] to be defined on unrelated objects.There can be only one special method with the name
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
2 in a class. Having more than one occurrence of a class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
2 method in a class will throw a class ValidationError extends Error {
printCustomerMessage[] {
return `Validation failed :-[ [details: ${this.message}]`;
}
}
try {
throw new ValidationError["Not a valid phone number"];
} catch [error] {
if [error instanceof ValidationError] {
console.log[error.name]; // This is Error instead of ValidationError!
console.log[error.printCustomerMessage[]];
} else {
console.log["Unknown error", error];
throw error;
}
}
2 error. Having a getter or setter called class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
2 is also a class ValidationError extends Error {
printCustomerMessage[] {
return `Validation failed :-[ [details: ${this.message}]`;
}
}
try {
throw new ValidationError["Not a valid phone number"];
} catch [error] {
if [error instanceof ValidationError] {
console.log[error.name]; // This is Error instead of ValidationError!
console.log[error.printCustomerMessage[]];
} else {
console.log["Unknown error", error];
throw error;
}
}
2.The
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
2 follows normal method syntax, so parameter default values, rest parameters, etc. can all be used.class Person {
constructor[name = "Anonymous"] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const person = new Person[];
person.introduce[]; // Hello, my name is Anonymous
The constructor must be a literal name. Computed properties cannot become constructors.
class Foo {
// This is a computed property. It will not be picked up as a constructor.
["constructor"][] {
console.log["called"];
this.a = 1;
}
}
const foo = new Foo[]; // No log
console.log[foo]; // Foo {}
foo.constructor[]; // Logs "called"
console.log[foo]; // Foo { a: 1 }
This code snippet is taken from the classes sample [live demo].
class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
0class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
8 calls the constructor that's the prototype of the current class. If you change the prototype of the current class itself, class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
8 will call the constructor of the new prototype. Changing the prototype of the current class's class ValidationError extends Error {
printCustomerMessage[] {
return `Validation failed :-[ [details: ${this.message}]`;
}
}
try {
throw new ValidationError["Not a valid phone number"];
} catch [error] {
if [error instanceof ValidationError] {
console.log[error.name]; // This is Error instead of ValidationError!
console.log[error.printCustomerMessage[]];
} else {
console.log["Unknown error", error];
throw error;
}
}
8 property doesn't affect which constructor class Person {
constructor[name] {
this.name = name;
}
introduce[] {
console.log[`Hello, my name is ${this.name}`];
}
}
const otto = new Person["Otto"];
otto.introduce[]; // Hello, my name is Otto
8 calls.