Свойство F.prototype и создание объектов через new

Объекты, помимо литеральной формы, создаются и функцией-конструктором черезnew. Посмотрим, как указать прототип в этом случае.


У всех функций по умолчанию есть публичное, неперечислимое свойство, называемое prototype, которое указывает на некий объект.

function Foo() {}

Foo.prototype; // { }

У каждого объекта, создаваемого с помощью вызова new Foo(), ссылка [[Prototype]]будет указывать на этот объект "Foo точка prototype".

function Foo() { // ... }

var a = new Foo();

Object.getPrototypeOf( a ) === Foo.prototype; // true

Вызов new Foo()создает новый объект (мы назвали его a), и этот новый объект aсвязан внутренней ссылкой [[Prototype]]с объектом Foo.prototype.


Механика

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

Foo.prototype.myName = function() {
  return this.name;
};

var a = new Foo( "a" );
var b = new Foo( "b" );

a.myName(); // "a"
b.myName(); // "b"

Этот пример показывает два дополнительных трюка для "класс-ориентированности":

  1. this.name = name: свойство .nameдобавляется в каждый объект (aиb, соответственно; привязкаthis), аналогично тому как экземпляры классов инкапсулируют значения данных.

  2. Foo.prototype.myName = ...: возможно более интересный прием, добавляет свойство (функцию) в объектFoo.prototype. Теперь работаетa.myName(), но каким образом?

В примере выше велик соблазн думать, что при созданииaиbсвойства/функции объектаFoo.prototypeкопируются в каждый из объектовaиb. Однако этого не происходит.

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

В силу того, как создаютсяaиb, оба объекта получают внутреннюю ссылку[[Prototype]]наFoo.prototype. КогдаmyNameне находится вaилиbсоответственно, она обнаруживается вFoo.prototype.

Еще пример:

var animal = {
  eats: true
};

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

Rabbit.prototype = animal;

var rabbit = new Rabbit("Кроль"); //  rabbit.__proto__ == animal

console.log( rabbit.eats ); // true

Установка Rabbit.prototype = animalбуквально говорит интерпретатору следующее: "При создании объекта через new Rabbitзапиши ему __proto__ = animal"


P.S:

В результате получилось два объекта (любой пример выше), связанных друг с другом. Вот и все. Мы не создали экземпляр класса. И мы уж точно не копировали никакого поведения из "класса" в реальный объект. Мы просто связали два объекта друг с другом.

На самом деле секрет, о котором не догадывается большинство JS разработчиков, состоит в том, что вызов функции new Foo()практически никак напрямую не связан с процессом создания ссылки. Это всегда было неким побочным эффектом. new Foo()— это косвенный, окольный путь к желаемому результату: новому объекту, связанному с другим объектом. Можем ли мы добиться желаемого более прямым путем? Да! Герой дня — Object.create(..). Но мы вернемся к нему чуть позже.

В JavaScript мы не делаем копии из одного объекта ("класса") в другой ("экземпляр"). Мы создаем ссылки между объектами.

results matching ""

    No results matching ""