The constructor property
The constructor
property is a built-in property of objects in JavaScript that points to the constructor function that created the instance object. This property plays a crucial role in the prototype chain, serving both for type checking and providing flexibility when dynamically creating objects.
Basic Concept of the constructor
Property
Every JavaScript object (except null
and undefined
) has a constructor
property, which by default points to the constructor function that created the object. For example:
const arr = [1, 2, 3];
console.log(arr.constructor === Array); // true
const num = 42;
console.log(num.constructor === Number); // true
function Person(name) {
this.name = name;
}
const person = new Person('Alice');
console.log(person.constructor === Person); // true
When using literal syntax to create objects, the JavaScript engine automatically calls the corresponding constructor, so the constructor
property remains valid:
const obj = {};
console.log(obj.constructor === Object); // true
const str = 'hello';
console.log(str.constructor === String); // true
The constructor
Property in the Prototype Chain
The constructor
property actually resides on the object's prototype object. Take the Person
constructor as an example:
function Person(name) {
this.name = name;
}
// The prototype object's constructor defaults to pointing to the constructor itself
console.log(Person.prototype.constructor === Person); // true
const person = new Person('Bob');
// The instance accesses constructor via the prototype chain
console.log(person.constructor === Person); // true
If the entire prototype object is overwritten, the constructor
reference must be manually restored:
function Animal(type) {
this.type = type;
}
// Incorrect approach: constructor is lost
Animal.prototype = {
eat() {
console.log('Eating...');
}
};
console.log(Animal.prototype.constructor === Animal); // false
// Correct approach: explicitly specify constructor
Animal.prototype = {
constructor: Animal,
eat() {
console.log('Eating...');
}
};
console.log(Animal.prototype.constructor === Animal); // true
Practical Use Cases of constructor
Alternative for Type Checking
Although instanceof
is more commonly used, constructor
can also be used for type checking:
function checkType(value) {
if (value.constructor === Array) {
return 'Array';
} else if (value.constructor === Object) {
return 'Object';
}
return typeof value;
}
console.log(checkType([])); // "Array"
console.log(checkType({})); // "Object"
Note: This method does not work for objects across different windows/iframes, as constructors from different global environments are not equal.
Dynamically Creating Objects of the Same Type
The constructor
property allows creating objects of the same type without knowing the specific type:
function clone(original) {
return new original.constructor();
}
const arr = [1, 2, 3];
const arrClone = clone(arr);
console.log(arrClone instanceof Array); // true
const date = new Date();
const dateClone = clone(date);
console.log(dateClone instanceof Date); // true
constructor
in Inheritance Systems
Properly handling constructor
is important when implementing inheritance:
function Parent(name) {
this.name = name;
}
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
// Incorrect inheritance: constructor points incorrectly
Child.prototype = Object.create(Parent.prototype);
console.log(Child.prototype.constructor === Parent); // true
// Correct inheritance: fix constructor
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const child = new Child('Charlie', 10);
console.log(child.constructor === Child); // true
Handling Special Cases
constructor
of Primitive Values
Primitive values (strings, numbers, etc.) undergo implicit boxing when accessing constructor
:
const str = 'hello';
console.log(str.constructor === String); // true
// Equivalent to:
const temp = new String(str);
console.log(temp.constructor === String); // true
Handling null
and undefined
These values do not have a constructor
property, and accessing it will throw an error:
try {
null.constructor;
} catch (e) {
console.error(e); // TypeError
}
Impact of Manually Modifying constructor
Modifying constructor
does not change the object's actual type but affects related operations:
function Foo() {}
function Bar() {}
const foo = new Foo();
foo.constructor = Bar;
console.log(foo instanceof Foo); // true
console.log(foo.constructor === Bar); // true
// Creating an object using the modified constructor
const fakeBar = new foo.constructor();
console.log(fakeBar instanceof Bar); // true
Integration with ES6 Classes
The ES6 class syntax automatically maintains the constructor
relationship:
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
}
class Square extends Rectangle {
constructor(size) {
super(size, size);
}
}
const square = new Square(5);
console.log(square.constructor === Square); // true
console.log(Square.prototype.constructor === Square); // true
Performance Considerations
Directly accessing constructor
is slightly faster than instanceof
, but the difference is negligible in modern JavaScript engines:
// Performance test example
const cycles = 1000000;
let start = performance.now();
for (let i = 0; i < cycles; i++) {
([]).constructor === Array;
}
console.log(`constructor: ${performance.now() - start}ms`);
start = performance.now();
for (let i = 0; i < cycles; i++) {
[] instanceof Array;
}
console.log(`instanceof: ${performance.now() - start}ms`);
Interaction with Other Features
Relationship with Symbol.species
The constructor
of built-in classes may be overridden by Symbol.species
:
class MyArray extends Array {
static get [Symbol.species]() {
return Array;
}
}
const myArr = new MyArray(1, 2, 3);
const mapped = myArr.map(x => x * 2);
console.log(mapped instanceof MyArray); // false
console.log(mapped.constructor === Array); // true
Comparison with new.target
new.target
reflects the constructor called at invocation, while constructor
reflects the instance's prototype relationship:
function A() {
console.log(new.target === A);
}
function B() {
A.call(this);
}
const a = new A(); // true
const b = new B(); // false
console.log(a.constructor === A); // true
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn