Выбрать главу

Рис. 18.5. Добавление промежуточного объекта person со свойством (теперь используемым совместно) getName

Заметьте, что теперь person стал частью цепочки прототипов, удачно расположившись между Object.prototype и нашими дочерними объектами. Как же это делается? Один из подходов мы уже видели ранее, и в нем мы опираемся на Object.create. При использовании Object.create мы можем указать объект, на основе которого требуется создать новый объект. Например:

let myObject = Object.create(fooObject);

Когда мы это делаем, за кадром происходит следующее: прототип нашего объекта myObject теперь будет fooObject. При этом он становится частью цепочки прототипов. Теперь, когда мы сделали крюк и расширили наше понимание Object.create, освоив содержание этой главы. Давайте вернемся к изначальному вопросу о том, как же именно наши объекты funnyGuy, theDude и detective наследуют от person.

Код, осуществляющий все это, будет таким:

let person = {

getName: function () {

return "The name is " + this.firstName + " " + this.lastName;

}

};

let funnyGuy = Object.create(person);

funnyGuy.firstName = "Conan";

funnyGuy.lastName = "O'Brien";

let theDude = Object.create(person);

theDude.firstName = "Jeffrey";

theDude.lastName = "Lebowski";

let detective = Object.create(person);

detective.firstName = "Adrian";

detective.lastName = "Monk";

Принцип работы цепочки прототипов позволяет нам вызывать getName для любого из наших объектов funnyGuy, theDude или detective, что приведет к ожидаемому результату:

detective.getName(); // Имя Adrian Monk

Если мы решим расширить объект person, то достаточно сделать это всего один раз, и это также отразится на всех наследующих от него объектах, не требуя дополнительного повторения. Предположим, мы хотим добавить метод getInitials, возвращающий первую букву из имени и фамилии:

let person = {

getName: function () {

return "The name is " + this.firstName + " " + this.lastName;

},

getInitials: function () {

if (this.firstName && this.lastName) {

return this.firstName[0] + this.lastName[0];

}

}

};

Мы добавляем метод getInitials в объект person. Чтобы использовать этот метод, можем вызвать его для любого объекта, расширяющего person, например funnyGuy:

funnyGuy.getInitials(); // CO

Такая возможность создавать промежуточные объекты, помогающие разделять функциональность кода, является мощным инструментом. Она повышает эффективность создания объектов и добавления в них функциональности. Неплохо, правда?

Ключевое слово this

В предыдущих фрагментах кода вы могли заметить использование ключевого слова this, особенно в случае с объектом person, где мы задействовали его для обращения к свойствам, созданным в его потомках, а не к его собственным. Давайте вернемся к этому объекту, а в частности к его свойству getName:

let person = {

getName: function () {

return "The name is " + this.firstName + " " + this.lastName;

},

getInitials: function () {

if (this.firstName && this.lastName) {

return this.firstName[0] + this.lastName[0];

}

}

};

Когда мы вызываем getName, то возвращаемое имя будет зависеть от того, из какого объекта мы это делаем. Например, если мы сделаем следующее:

let spaceGuy = Object.create(person);

spaceGuy.firstName = "Buzz";

spaceGuy.lastName = "Lightyear";

console.log(spaceGuy.getName()); // Buzz Lightyear

При выполнении этого кода мы увидим в консоли Buzz Lightyear. Если мы еще раз взглянем на свойство getName, то увидим, что там нет свойств firstName и lastName в объекте person. Но как мы видели ранее, если свойство не существует, мы переходим далее по цепочке от родителя к родителю, как показано на рис. 18.6.

Рис. 18.6. Цепочка прототипов для объекта person

В нашем случае единственной остановкой в цепочке будет Object.prototype, но в нем также не обнаруживаются свойства firstName и lastName. Как же тогда метод getName умудряется сработать и вернуть нужные значения?

Ответ заключается в ключевом слове this, предшествующем firstName и lastName в инструкции return метода getName:

let person = {

getName: function () {

return "The name is " + this.firstName + " " + this.lastName;

},

getInitials: function () {