Object.prototype.constructor

Повертає посилання на функцію-конструктор об'єкта, що створила екземпляр об'єкта. Зауважте, що значення цієї властивості є посиланням на саму функцію, а не рядком, що містить ім'я функції. Значення, доступне лише для читання, мають лише примітивні значення, як то 1true або "test".

Опис

Усі об'єкти (за виключенням об'єктів, створених через Object.create(null)) матимуть властивість constructor. Об'єкти, створені без явного використання функції-конструктора (тобто, об'єктними та масивними літералами), матимуть властивість constructor, що вказує на конструктор фундаментального об'єкта для цього об'єкта.

var o = {};
o.constructor === Object; // true

var o = new Object;
o.constructor === Object; // true

var a = [];
a.constructor === Array; // true

var a = new Array;
a.constructor === Array; // true

var n = new Number(3);
n.constructor === Number; // true

Приклади

Відображення конструктора об'єкта

Наступний приклад створює конструктор Tree та об'єкт цього типу, theTree. Далі приклад демонструє властивість constructor об'єкта theTree.

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

var theTree = new Tree('Redwood');
console.log('theTree.constructor дорівнює ' + theTree.constructor);

Цей приклад виведе наступний результат:

theTree.constructor дорівнює function Tree(name) {
  this.name = name;
}

Зміна конструктора об'єкта

Наступний приклад покаже як можна змінити конструктор загальних об'єктів. Тільки true, 1 та "test" не зміняться, оскілки їхні конструктори доступні лише для читання. Цей приклад демонструє, що не завжди безпечно покладатися на властивість об'єкта constructor.

function Type () {}

var types = [
  new Array(),
  [],
  new Boolean(),
  true,             // лишається незмінним
  new Date(),
  new Error(),
  new Function(),
  function () {},
  Math,
  new Number(),
  1,                // лишається незмінним
  new Object(),
  {},
  new RegExp(),
  /(?:)/,
  new String(),
  'test'            // лишається незмінним
];

for (var i = 0; i < types.length; i++) {
  types[i].constructor = Type;
  types[i] = [types[i].constructor, types[i] instanceof Type, types[i].toString()];
}

console.log(types.join('\n'));

Цей приклад виведе наступний результат (коментарі додані для довідки):

function Type() {},false,                                     // new Array()
function Type() {},false,                                     // []
function Type() {},false,false                                // new Boolean()
function Boolean() {
    [native code]
},false,true                                                  // true
function Type() {},false,Mon Sep 01 2014 16:03:49 GMT+0600    // new Date()
function Type() {},false,Error                                // new Error()
function Type() {},false,function anonymous() {

}                                                             // new Function()
function Type() {},false,function () {}                       // function () {}
function Type() {},false,[object Math]                        // Math
function Type() {},false,0                                    // new Number()
function Number() {
    [native code]
},false,1                                                     // 1
function Type() {},false,[object Object]                      // new Object()
function Type() {},false,[object Object]                      // {} 
function Type() {},false,/(?:)/                               // new Regexp()
function Type() {},false,/(?:)/                               // /(?:)/ 
function Type() {},false,                                     // new String()
function String() {
    [native code]
},false,test

Зміна конструктора функції

Переважно ця властивість використовується для визначення функції як функції-конструктора з подальшим викликом її з оператором new та наслідуванням через ланцюжок прототипів.

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

function Child() {}
Child.prototype = Object.create(Parent.prototype); // перевизначення дочірнього прототипу на прототип Parent

Child.prototype.constructor = Child; // повернення початкового конструктора прототипу Child

Але коли нам потрібно виконувати цей останній рядок? Нажаль, відповідь - залежить від обставин.

Спробуємо визначити випадки, коли переприсвоєння початкового конструктора зіграє важливу роль, а коли воно стане додатковим непотрібним рядком коду.

Візьмемо наступний випадок: об'єкт має метод create для створення самого себе.

function Parent() {};
function CreatedConstructor() {}

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

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

new CreatedConstructor().create().create(); // TypeError undefined is not a function, оскільки constructor === Parent

У наведеному вище прикладі виняток виникне тому, що конструктор посилається на Parent.

Щоб уникнути цього, просто призначте потрібний конструктор, який ви збираєтесь використовувати.

function Parent() {};
function CreatedConstructor() {} 

CreatedConstructor.prototype = Object.create(Parent.prototype);
CreatedConstructor.prototype.constructor = CreatedConstructor; // призначте конструктор, який будете використовувати

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

new CreatedConstructor().create().create(); // так непогано

Гаразд, тепер зрозуміло, чому зміна конструктора може бути досить корисною.

Розглянемо інший випадок.

function ParentWithStatic() {}

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

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

Child.prototype = Object.create(ParentWithStatic.prototype);
Child.prototype.constructor = Child;

Child.prototype.getOffsetByInitialPosition = function getOffsetByInitialPosition() {
  var position = this.position;
  var startPosition = this.constructor.getStartPosition(); // error undefined is not a function, оскільки конструктор - Child

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

В цьому прикладі нам треба залишити батьківський конструктор, щоб все працювало як слід.

Висновок: ручна зміна або встановлення конструктора може призвести до різноманітних та іноді заплутаних наслідків. Щоб запобігти цьому, визначте роль конструктора у кожному конкретному випадку. В більшості випадків конструктор не використовується, і в перепризначенні немає необхідності.

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

Специфікація Статус Коментар
ECMAScript Latest Draft (ECMA-262)
The definition of 'Object.prototype.constructor' in that specification.
Draft
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Object.prototype.constructor' in that specification.
Standard
ECMAScript 5.1 (ECMA-262)
The definition of 'Object.prototype.constructor' in that specification.
Standard
ECMAScript 1st Edition (ECMA-262) Standard Початкове визначення. Реалізоване у JavaScript 1.1.

Сумісність з веб-переглядачами

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
constructorChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 4Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes

Legend

Full support  
Full support