Spec-Zone.ru › JavaScript

Object.prototype.constructor

Базовая версия Широко доступна

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна во всех браузерах с июля 2015 года.

Свойство данных constructor экземпляра Object возвращает ссылку на функцию-конструктор, которая создала объект-экземпляр. Обратите внимание, что значение этого свойства является ссылкой на саму функцию, а не строкой, содержащей имя функции.

Примечание: Это свойство объектов JavaScript. О методе constructor в классах смотрите на его отдельной странице справки.

Значение

Ссылка на функцию-конструктор, которая создала объект-экземпляр.

Атрибуты свойства Object.prototype.constructor
Записываемое да
Перечисляемое нет
Конфигурируемое да

Примечание: Это свойство создаётся по умолчанию в свойстве prototype каждой функции-конструктора и наследуется всеми объектами, созданными этим конструктором.

Описание

Любой объект (за исключением объектов с null прототипом) будет иметь свойство constructor в своём [[Prototype]]. Объекты, созданные с помощью литералов, также будут иметь свойство constructor, которое указывает на тип конструктора для этого объекта — например, литералы массивов создают объекты Array, а литералы объектов создают простые объекты.

const o1 = {};
o1.constructor === Object; // true

const o2 = new Object();
o2.constructor === Object; // true

const a1 = [];
a1.constructor === Array; // true

const a2 = new Array();
a2.constructor === Array; // true

const n = 3;
n.constructor === Number; // true

Обратите внимание, что constructor обычно исходит из свойства prototype конструктора. Если у вас более длинная цепочка прототипов, вы обычно можете ожидать, что каждый объект в цепочке будет иметь свойство constructor.

const o = new TypeError(); // Inheritance: TypeError -> Error -> Object
const proto = Object.getPrototypeOf;

Object.hasOwn(o, "constructor"); // false
proto(o).constructor === TypeError; // true
proto(proto(o)).constructor === Error; // true
proto(proto(proto(o))).constructor === Object; // true

Примеры

Отображение конструктора объекта

Следующий пример создает конструктор (Tree) и объект этого типа (theTree). Затем пример отображает свойство constructor для объекта theTree.

function Tree(name) {
  this.name = name;
}

const theTree = new Tree("Redwood");
console.log(`theTree.constructor is ${theTree.constructor}`);

Этот пример выводит следующий результат:

theTree.constructor is function Tree(name) {
  this.name = name;
}

Присвоение свойства constructor объекту

Можно присвоить свойство constructor непримитивным значениям.

const arr = [];
arr.constructor = String;
arr.constructor === String; // true
arr instanceof String; // false
arr instanceof Array; // true

const foo = new Foo();
foo.constructor = "bar";
foo.constructor === "bar"; // true

// etc.

Это не перезаписывает старое свойство constructor — оно изначально присутствовало в [[Prototype]] экземпляра, а не как его собственное свойство.

const arr = [];
Object.hasOwn(arr, "constructor"); // false
Object.hasOwn(Object.getPrototypeOf(arr), "constructor"); // true

arr.constructor = String;
Object.hasOwn(arr, "constructor"); // true — the instance property shadows the one on its prototype

Но даже если Object.getPrototypeOf(a).constructor будет переназначен, это не изменит другого поведения объекта. Например, поведение instanceof контролируется Symbol.hasInstance, а не constructor:

const arr = [];
arr.constructor = String;
arr instanceof String; // false
arr instanceof Array; // true

Нет ничего, что защищало бы свойство constructor от переназначения или затенения, поэтому использование его для определения типа переменной обычно следует избегать в пользу менее хрупких способов, таких как instanceof и Symbol.toStringTag для объектов, или typeof для примитивов.

Изменение конструктора прототипа функции-конструктора

Каждый конструктор имеет свойство prototype, которое станет [[Prototype]] экземпляра при вызове с помощью оператора new. Следовательно, ConstructorFunction.prototype.constructor станет свойством в [[Prototype]] экземпляра, как было показано ранее.

Однако, если ConstructorFunction.prototype будет переназначен, свойство constructor будет потеряно. Например, ниже приведен распространенный способ создания шаблона наследования:

function Parent() {
  // …
}
Parent.prototype.parentMethod = function () {};

function Child() {
  Parent.call(this); // Make sure everything is initialized properly
}
// Pointing the [[Prototype]] of Child.prototype to Parent.prototype
Child.prototype = Object.create(Parent.prototype);

constructor экземпляров Child будет равно Parent из-за переназначения Child.prototype.

Обычно это не имеет большого значения — язык почти никогда не считывает свойство constructor объекта. Единственное исключение — это использование [Symbol.species] для создания новых экземпляров класса, но такие случаи редки, и вам в любом случае следует использовать синтаксис extends для создания подклассов встроенных объектов.

Однако, крайне важно обеспечить, чтобы Child.prototype.constructor всегда указывал на сам Child, когда некий вызывающий код использует constructor для доступа к исходному классу из экземпляра. Рассмотрим следующий случай: объект имеет метод create() для создания самого себя.

function Parent() {
  // …
}
function CreatedConstructor() {
  Parent.call(this);
}

CreatedConstructor.prototype = Object.create(Parent.prototype);

CreatedConstructor.prototype.create = function () {
  return new this.constructor();
};

new CreatedConstructor().create().create(); // TypeError: new CreatedConstructor().create().create is undefined, since constructor === Parent

В приведенном выше примере выбрасывается исключение, так как constructor ссылается на Parent. Чтобы избежать этого, просто назначьте необходимый конструктор, который вы собираетесь использовать.

function Parent() {
  // …
}
function CreatedConstructor() {
  // …
}

CreatedConstructor.prototype = Object.create(Parent.prototype, {
  // Return original constructor to Child
  constructor: {
    value: CreatedConstructor,
    enumerable: false, // Make it non-enumerable, so it won't appear in `for...in` loop
    writable: true,
    configurable: true,
  },
});

CreatedConstructor.prototype.create = function () {
  return new this.constructor();
};

new CreatedConstructor().create().create(); // it's pretty fine

Обратите внимание, что при ручном добавлении свойства constructor крайне важно сделать свойство неперечисляемым, чтобы constructor не посещалось в циклах for...in — как это обычно и происходит.

Если приведенный выше код кажется слишком шаблонным, вы также можете рассмотреть возможность использования Object.setPrototypeOf() для манипулирования цепочкой прототипов.

function Parent() {
  // …
}
function CreatedConstructor() {
  // …
}

Object.setPrototypeOf(CreatedConstructor.prototype, Parent.prototype);

CreatedConstructor.prototype.create = function () {
  return new this.constructor();
};

new CreatedConstructor().create().create(); // still works without re-creating constructor property

Object.setPrototypeOf() имеет потенциальные недостатки в производительности, потому что все ранее созданные объекты, участвующие в цепочке прототипов, должны быть перекомпилированы; но если приведенный выше код инициализации выполняется до того, как будут сконструированы Parent или CreatedConstructor, эффект должен быть минимальным.

Рассмотрим еще один более сложный случай.

function ParentWithStatic() {}

ParentWithStatic.startPosition = { x: 0, y: 0 }; // Static member property
ParentWithStatic.getStartPosition = function () {
  return this.startPosition;
};

function Child(x, y) {
  this.position = { x, y };
}

Child.prototype = Object.create(ParentWithStatic.prototype, {
  // Return original constructor to Child
  constructor: {
    value: Child,
    enumerable: false,
    writable: true,
    configurable: true,
  },
});

Child.prototype.getOffsetByInitialPosition = function () {
  const position = this.position;
  // Using this.constructor, in hope that getStartPosition exists as a static method
  const startPosition = this.constructor.getStartPosition();

  return {
    offsetX: startPosition.x - position.x,
    offsetY: startPosition.y - position.y,
  };
};

new Child(1, 1).getOffsetByInitialPosition();
// Error: this.constructor.getStartPosition is undefined, since the
// constructor is Child, which doesn't have the getStartPosition static method

Чтобы этот пример работал правильно, мы можем переназначить статические свойства Parent в Child:

// …
Object.assign(Child, ParentWithStatic); // Notice that we assign it before we create() a prototype below
Child.prototype = Object.create(ParentWithStatic.prototype, {
  // Return original constructor to Child
  constructor: {
    value: Child,
    enumerable: false,
    writable: true,
    configurable: true,
  },
});
// …

Но еще лучше, мы можем заставить сами функции-конструкторы расширять друг друга, как это делает extends классов.

function ParentWithStatic() {}

ParentWithStatic.startPosition = { x: 0, y: 0 }; // Static member property
ParentWithStatic.getStartPosition = function () {
  return this.startPosition;
};

function Child(x, y) {
  this.position = { x, y };
}

// Properly create inheritance!
Object.setPrototypeOf(Child.prototype, ParentWithStatic.prototype);
Object.setPrototypeOf(Child, ParentWithStatic);

Child.prototype.getOffsetByInitialPosition = function () {
  const position = this.position;
  const startPosition = this.constructor.getStartPosition();

  return {
    offsetX: startPosition.x - position.x,
    offsetY: startPosition.y - position.y,
  };
};

console.log(new Child(1, 1).getOffsetByInitialPosition()); // { offsetX: -1, offsetY: -1 }

Опять же, использование Object.setPrototypeOf() может иметь неблагоприятные последствия для производительности, поэтому убедитесь, что это происходит сразу после объявления конструктора и до создания каких-либо экземпляров — чтобы избежать «испорченности» объектов.

Примечание: Ручное обновление или установка конструктора может привести к различным, а иногда и запутанным последствиям. Чтобы предотвратить это, просто определите роль constructor в каждом конкретном случае. В большинстве случаев constructor не используется, и его переназначение не требуется.

Спецификации

Спецификация
Спецификация языка ECMAScript® 2027
# sec-object.prototype.constructor

Совместимость с браузерами

Настольные ПК Мобильные устройства Серверы
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
constructor
1
12
1
4
1
18
4
10.1
1
1.0
4.4
1
1.0.0
1.0
0.10.0

Смотрите также

  • class
  • constructor
  • Конструктор

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API