Прототипное наследование в JavaScript

В этом руководстве вы узнаете, как работает прототипное наследование в JavaScript.

Если вы работали с другими объектно-ориентированными языками программирования, такими как Java или C++, вы знакомы с концепцией наследования.

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

JavaScript не использует классическое наследование. Вместо этого он использует прототипное наследование.

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

Наследование прототипов JavaScript и __proto__

Давайте рассмотрим пример, чтобы прояснить концепцию.

Определяем объект person :

let person = {
    name: "John Doe",
    greet: function() {
        return "Hi, I'm " + this.name;
    }
};

В этом примере объект person имеет свойство и метод:

  • name — это свойство, в котором хранится имя человека.
  • greet — это метод, который возвращает приветствие в виде строки.

По умолчанию движок JavaScript предоставляет вам встроенную функцию Object() и анонимный объект, на который может ссылаться Object.prototype :

JavaScript-прототип

Обратите внимание, что кружок представляет собой функцию, а квадрат — объект.

Объект person имеет ссылку на анонимный объект, на который ссылается функция Object(). [[Prototype]] представляет связь:

Наследование прототипов JavaScript

Это означает, что объект person может вызывать любые методы, определенные в анонимном объекте, на который ссылается Object.prototype. Например, ниже показано, как вызвать метод toString() через объект person :

console.log(person.toString());

Выход:

[object Object]

[object Object] — это строковое представление объекта по умолчанию.

Когда вы вызываете метод toString() через person, движок JavaScript не может найти его в объекте person. Поэтому движок JavaScript следует цепочке прототипов и ищет метод в объекте Object.prototype.

Поскольку механизм JavaScript может найти метод toString() в объекте Object.prototype, он выполняет метод toString().

Чтобы получить доступ к прототипу объекта person, вы можете использовать свойство __proto__ следующим образом.

console.log(person.__proto__);

Ниже показано, что person.__proto__ и Object.prototype ссылаются на один и тот же объект:

console.log(person.__proto__ === Object.prototype);
 // true

Следующий код определяет объект teacher, который имеет метод teach() :

let teacher = {
    teach: function(subject) {
        return "I can teach " + subject;
    }
};

Как и объект person, teacher.__proto__ ссылается на Object.prototype, как показано на следующем рисунке:

teacher.__proto__ ссылается на Object.prototype

Если вы хотите, чтобы объект teacher имел доступ ко всем методам и свойствам объекта person, вы можете установить прототип объекта teacher для объекта person следующим образом:

teacher.__proto__ = person;

Доступ ко всем методам и свойствам

Обратите внимание, что вы никогда не должны использовать свойство __proto__ в производственном коде. Пожалуйста, используйте его только в демонстрационных целях.

Теперь объект teacher может получить доступ к свойству name и методу greet() из объекта person через цепочку прототипов:

console.log(teacher.name); 
console.log(teacher.greet());

Выход:

John Doe 
Hi, I'm John Doe

Когда вы вызываете метод greet() для объекта teacher, движок JavaScript сначала находит его в объекте teacher.

Поскольку движок JavaScript не может найти метод в объекте teacher, он следует по цепочке прототипов и ищет метод в объекте person. Движок JavaScript может найти метод greet() в объекте person, он выполняет этот метод.

В JavaScript мы говорим, что объект « teacher » наследует методы и свойства объекта « person ». И этот вид наследования называется прототипным наследованием.

Стандартный способ реализации в ES5

ES5 предоставляет стандартный способ работы с прототипным наследованием с помощью Object.create().

Обратите внимание, что теперь вы должны использовать более новый class ES6 и ключевые слова extends для реализации наследования. Это намного проще.

Метод Object.create() создает новый объект и использует существующий объект в качестве прототипа нового объекта:

Object.create(proto, [propertiesObject])

Метод Object.create() принимает два аргумента:

  • Первый аргумент( proto ) — это объект, используемый в качестве прототипа для нового объекта.
  • Второй аргумент( propertiesObject ), если он предоставлен, является необязательным объектом, который определяет дополнительные свойства для нового объекта.

Предположим, у вас есть объект person :

let person = {
    name: "John Doe",
    greet: function() {
        return "Hi, I'm " + this.name;
    }
};

Создадим пустой объект teacher с __proto__ объекта person :

let teacher = Object.create(person);

После этого вы можете определить свойства для объекта teacher :

teacher.name = 'Jane Doe';
teacher.teach = function(subject) {
    return "I can teach " + subject;
}

Или вы можете сделать все эти шаги в одном выражении следующим образом:

let teacher = Object.create(person, {
    name: {
        value: 'John Doe'
    },
    teach: {
        value: function(subject) {
            return "I can teach " + subject;
        }
    }
});

В ES5 также появился метод Object.getPrototypeOf(), который возвращает прототип объекта. Например:

console.log(Object.getPrototypeOf(teacher) === person);

Выход:

true

Заключение

  • Наследование позволяет объекту использовать свойства и методы другого объекта без дублирования кода.
  • JavaScript использует прототипное наследование.
Рейтинг
( Пока оценок нет )
Александр Русаков / автор статьи
Программист, разработчик, 12 лет опыта работы в крупных компаниях. Быстро освоил typescript, делюсь своими знаниями на страницах этого сайта.
Загрузка ...
JavaScript и TypeScript