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 не используется, и его переназначение не требуется.
Спецификации
Совместимость с браузерами
| Настольные ПК | Мобильные устройства | Серверы | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 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 |
Смотрите также
© 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