Наследство — не то, что оставит тебе папа, а это
в основном используется для уменьшения дублирования кода. Обычно это связано с классами, и если вы когда-либо программировали на каком-либо языке, таком как Java, вы можете быть знакомы с этой концепцией, но в JS это можно сделать с классами или без них. Тем не менее, я расскажу об обоих способах и попытаюсь понять концепцию наследования.
Предположим, у нас есть два чистых объекта, имеющих простую функцию talk.
const me = { talk() { return 'talking' } } consts you = { talk() { return 'talking' } }
Итак, мы с тобой оба люди, и мы оба можем говорить. Здесь у нас есть 2 основные проблемы. Во-первых, проблема заключается в том, что мы называем дублированием кода, то есть нам пришлось написать функцию talk() дважды, один раз для вас и один для меня :D
Я имею в виду, в чем проблема с этим? это всего лишь одна строка кода, которую я напишу дважды. Как программист, важно признать, что повторение кода должно быть сведено к минимуму, учитывая сложность реальных функций, где краткие однострочники не являются нормой. Логика обычно сложнее. Итак, вместо 2 строк предположим, что у нас есть 100 строк кода, а у вас получится 200 строк. Но даже тогда разумно сказать, ну и что?? , я просто скопирую строки и вставлю их. Например, допустим, у нас есть объект «я», объект «ты», объект «она» и объект «он» или объект «они/они». Нам пришлось бы копировать функциональность для каждого отдельного объекта, что привело бы к большому дублированию кода. В реальных проектах это большое нет.
Вторая проблема заключается в том, что, допустим, у нас есть ошибка или нам нужно обновить функцию, нам не нужно делать это в одном месте. Нам придется сделать это везде.
Итак, чтобы исправить это, у нас есть концепция наследования. Начнем с наследования на основе классов.
class Person { talk() { return 'talking'; } }
а затем я могу создать несколько объектов, используя шаблон класса Person.
const me = new Person(); const you = new Person(); const lgtv = new Person(); me.talk(); you.talk(); lgtv.talk();
Это решает изначальную проблему дублирования кода. Теперь вопрос обновления функции, так как мы можем это исправить? Были ли какие-либо проблемы с функцией? я должен сделать, как me.talk = someotherfunction()
вы можете спросить?
мы можем это сделать, но мы действительно не должны. Давайте посмотрим, почему.
давайте посмотрим на объект меня, утешив его.
console.log(me);
который имеет тип Person, на нем нет функции разговора, вы можете видеть, что на нем есть что-то под названием Prototype. Если мы откроем прототип, то увидим на нем кое-что интересное.
У нас есть конструктор, и наша собственная функция разговора, и некоторые другие вещи, но дело в том, что у меня непосредственно нет функции разговора. и если мы сделаем один шаг и скажем me.age=12
ну тогда,
возраст виден, а разговоров нет. это означает, что речь идет о нашем прототипе, классе, который мы унаследовали. поэтому, если мы действительно хотим что-то изменить в функции разговора, нам придется подключиться к прототипу.
Имейте это в виду, пока давайте посмотрим на наш класс Person. Это действительно не очень сильно проявляется.
Но если мы утешим Person.prototype
, мы увидим некоторые знакомые вещи, которые мы видели на мне.
и вы можете спросить сейчас, они похожи? давайте посмотрим на это.
так что они одно и то же. значение,
поэтому, возвращаясь к нашей первоначальной проблеме, если мы хотим исправить ошибку или улучшить функцию разговора, нам нужно будет сделать
и если мы вызовем нашу функцию me.talk()
, мы получим
Вот это хороший разговор :3
и это в некотором смысле то, как наследование на основе классов работает в JS, по сути, это просто создание шаблона, от которого вы можете наследовать.
Теперь давайте на секунду отложим в сторону классы и поговорим о чистых объектах и прототипах, которые дадут вам немного больше понимания о прототипах :3
Теперь другой способ наследования или основной способ наследования в Js — это то, что вы, возможно, слышали, через чистые объекты или то, что мы называем прототипным наследованием. На самом деле, в предыдущем примере, который мы взяли, используются объекты и функции, а также прототипы внизу, даже несмотря на то, что мы используем ключевое слово class, и это то, что мы называем синтаксическим сахаром, что означает, что на самом деле это не классы. Это просто удобный способ чтения и написания шаблона, потому что синтаксис объектов и Prototypal Inheritance в Js немного раздражает и странен.
Говоря о прототипном наследовании, давайте посмотрим, как оно работает внутри.
когда мы пишем class Person () {}
, то, что делает Js ниже, это то, что он создает функцию с именем Person, напрямую переходит к ее прототипу и добавляет эту функцию Talk для вас.
и если мы сделаем const me=new Person();
это дает нам тот же результат, и если мы посмотрим на меня
это точно такая же идея. Мы говорим не об объекте, а о его прототипе.
Другой способ добиться этого — сказать:
и me.talk
все еще работает. Впрочем, здесь есть разница, если утешить меня возражением.
разговор идет прямо о предмете, но что это значит? и почему это вообще важно?
Что ж, то, что мы только что создали, является объектом-конструктором, и все, что мы добавим к этому объекту, не будет рассматриваться как метод, оно будет рассматриваться как свойство, такое же, как строка, логическое значение или число. Таким образом, функция, для которой вы написали логику, фактически копируется в этот экземпляр или дочерний объект. В то время как если вы добавите его в качестве прототипа, он будет считаться методом. Так что плохого в том, чтобы иметь это как собственность? Технически доступ к нему осуществляется так же, как мы видели. Но, как я уже сказал, он копируется во все экземпляры или дочерние объекты.
Это означает, что если вы когда-нибудь захотите изменить или модифицировать эту функцию, вам придется изменять ее в каждом экземпляре, что потеряет цель наследования.
Точно так же обновление свойства объекта не будет каскадным во всех других экземплярах этого объекта.
Давайте возьмем другой пример, чтобы то, что я говорю, имело больше смысла.
давайте определим функцию-конструктор со свойством age равным 12. Затем определим объект me как Person, и мы увидим, что у объекта me уже есть свойство age равное 12. Теперь, если мы скажем, Person.age=40
, и если мы утешим и человека, и меня.
мне объект все еще имеет возраст 12. Итак, что здесь произошло? Я думал, что просто поменял.
Ну, а если присмотреться,
Человек фактически не имеет возраста ни на себе, ни на своем прототипе. Это просто свойство объекта, который является экземпляром этой функции Person. , Он принадлежит только мне и получает добавленный ко мне объект.
Итак, это очень удобный способ добавить все свойства к объекту this внутри конструктора и все методы к его прототипам.
Это также дает нам четкое представление о моих вещах, возрасте, имени, поле и т. д., а также обо всех методах/поведении, которые у меня есть.
Давайте теперь взглянем на еще одну замечательную возможность, которую дает нам наследование. расширяется
Допустим, вы хотите одолжить куртку своего друга, но использовать свой нагрудный платок, и наследование позволяет нам делать то же самое.
скажем
class Person { talk() { return 'talking'; } } const me = new Person();
и теперь у нас есть, скажем, еще один класс, расширяющий Person.
class SuperPerson extends Person { fly() { return 'I can Fly!!!'; } }
а теперь, мой друг, ты Суперчеловек.
const you=new SuperPerson();
Итак, давайте посмотрим, работает не только you.fly()
, но и you.talk()
:D, что довольно интересно, потому что у SuperPerson нет функции разговора, но он расширяет класс Person, у которого есть функция разговора. Однако me.fly()
не сработает, потому что я всего лишь человек.
Наконец, у нас есть чистое наследование объектов.
const Person = { talk() { return 'talking'; } }
Итак, как я могу создать объект «я», который является экземпляром этого человека, и использовать функцию разговора?
для этого, мы можем сказать,
const me = Object.create(Person);
другой способ, которым мы можем добиться того же, говоря.
const me = {} //Just a pure object. Object.setPrototypeOf(me, Person);// where the first parameter is instance // and second parameter is just the parent // where you want to inherit from
Вывод:3
Почему наследование, Где наследование?
Итак, где мы используем наследование? хорошо, если у вас есть объекты с общим или похожим поведением, или компоненты с похожей функциональностью, возможно, в обработчиках событий, clickHandlers, где каждый раз, когда вы делаете это, вы создаете шаблон, который можно повторно использовать снова и снова, просто создав класс шаблона и вызывать нужные методы, а класс позаботится об этом за вас.
Несмотря на то, что о наследовании можно рассказать еще много, надеюсь, вы уловили суть.