Синтаксис JavaScript Справочник JavaScript Коды клавиш События Строгий режим

JavaScript: constructor и prototype

Шаблон "Конструктор"

function User(name, age) {
  this.name = name;
  this.age = age;
  this.sayHi = function () {
    console.log("Hello!");
  }
}

let user = new User("Homer", 33);
console.log(user.name);

У каждого объекта, созданного с помощью конструктора, есть неявно добавленное свойство constructor, содержащее ссылку на конструктор, с помощью которого был создан объект:

console.log(user.constructor === User);   // true

Свойство constructor предназначено для идентификации типа объекта. Тоже самое позволяет сделать оператор instanceof:

console.log(user instanceof User);   // true

При использовании конструктора для создания объекта, для каждого созданного объекта создаётся своя копия свойств и методов.

Шаблон "Прототип"

Когда создаётся функция, в неё по умолчанию добавляется свойство prototype. Значением свойства prototype является объект, содержащий общие свойства и методы, которые доступны всем объектам, созданным с помощью этого конструктора.

Вместо того, чтобы указывать свойства и методы в конструкторе, их можно указать непосредственно прототипу:

function User() {}
User.prototype.name = "Homer";
User.prototype.age = "33";
User.prototype.sayHi = function () {
  console.log("Hello!");
};

let user = new User();
console.log(user.name);

По умолчанию все прототипы имеют только свойство constructor, содержащее ссылку на функцию, к которой оно относится:

function foo() {}
console.log(foo.prototype.constructor === foo);   // true

Все остальные методы и свойства наследуются от типа Object. Когда с помощью конструктора создаётся новый объект, в нём определяется внутренний указатель (ссылка) на прототип конструктора. Доступ к этому указателю можно получить с помощью метода Object.getPrototypeOf():

function foo() {}
let obj = new foo();
console.log(Object.getPrototypeOf(obj) === foo.prototype);   // true

При чтении свойства объекта начинается его поиск. Сначала свойство с указанным именем ищется в самом объекте. Если оно обнаруживается у объекта, возвращается значение свойства, если свойства с таким именем нет у объекта, поиск продолжается в прототипе. В случае обнаружения свойства у прототипа возвращается его значение. Так прототипы обеспечивают совместное использование свойств и методов у объектов.

Если в объект добавить свойство с именем, как у свойства прототипа, то у объекта будет создано собственное свойство, в этом случае при следующем чтении свойства будет использоваться свойство объекта, а не прототипа.

Чтобы писать меньше кода, можно перезаписать прототип литералом объекта, содержащим все свойства и методы:

function User() {}
User.prototype = {
  name: "Homer",
  age: 33,
  sayHi: function () {
    console.log("Hello!");
  }
};

// Восстановление свойства constructor
Object.defineProperty(User.prototype, "constructor", {
  enumerable: false,
  value: User
});

В этом примере свойству User.prototype присваивается новый объект, созданный с помощью литерала. Он полностью заменяет собою объект, предлагаемый по умолчанию. Результат получается таким же, как и в предыдущем примере, за одним исключением: свойство constructor больше не указывает на функцию User. Явное добавление свойства constructor со значением User в литерал объекта решает эту проблему. Свойство constructor у встроенных объектов по умолчанию неперечислимо, поэтому для его добавления использовался метод Object.defineProperty().

Объединение шаблонов "конструктор" и "прототип"

С помощью конструктора определяют собственные свойства, а с помощью прототипа – общие методы и свойства:

function User(name, age) {
  this.name = name;
  this.age = age;
}

User.prototype.sayHi = function () {
  console.log("Hello!");
}
Копирование материалов с данного сайта возможно только с разрешения администрации сайта
и при указании прямой активной ссылки на источник.
2011-2016 © puzzleweb.ru

Реклама на сайте | Обратная связь