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
  }
};

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

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

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

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

BCD tables only load in the browser