阿里云主机折上折
  • 微信号
Current Site:Index > The constructor property

The constructor property

Author:Chuan Chen 阅读数:3616人阅读 分类: JavaScript

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

上一篇:原型与原型链

下一篇:继承实现方式

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.