Привет друзья😀

Когда я изучал Javascript, мне всегда было интересно, когда я определяю строку или функцию и т. д.… как можно получить некоторые свойства и методы, такие как длина, поиск, forEach или любые другие методы?? Когда мы видим закулисье, мы понимаем, откуда все это взялось. Наконец, мы узнаем немного об oop в javascript и о том, что именно происходит под капотом.

Итак, мы рассмотрим oop в javascript в двух частях. Первая часть будет посвящена прототипу и настройке oop, а вторая часть посвящена oop в javascript.

Javascript — это объектно-ориентированный язык, основанный на прототипах, в отличие от других языков, основанных на классах.
Из-за этого иерархия и наследование объектов Javascript несколько странные и сложные. Но что такое прототипы?
Давайте начнем наше путешествие с простого примера:

Здесь я объявил объект и зарегистрировал три его свойства. Но подождите минутку! Я только что объявил свойство имени и возраста, откуда, черт возьми, этот метод hasOwnProperty (свойство объекта, которое является функцией, называемой методом)? Хммм…🤔 давайте зарегистрируем весь объект, чтобы увидеть, что он включает в себя:

Ну-ну, посмотрите, кто здесь, теперь мы можем видеть, когда мы определяем объект, javascript дает ему скрытое, но доступное свойство, которое является объектом и называется __proto__. Теперь давайте посмотрим на свойство __proto___:

Здесь мы можем увидеть метод hasOwnPropert и некоторые другие методы. Интересно, что если мы определим тысячи объектов с миллионами свойств, во всех из них все равно будет еще одно свойство по умолчанию, а именно этот объект со всеми этими методами, и этот объект называется «прототип глобального объекта» и более того. Интересно, что javascript не собирается определять или, другими словами, дублировать этот объект для каждого объекта, который мы определяем, он просто дает им свойство __proto__, которое ссылается на прототип глобального объекта, и, другими словами, наследует прототип глобального объекта, поэтому он гарантирует не взрывать память и, что гораздо интереснее, если мы посмотрим на глобальный прототип объекта, он сам имеет свойство __proto__! Хотя это null и своего рода ссылка на тупик, дело в том, что нет объекта, у которого не было бы __proto__. Javascript полон интересных вещей :)

Давайте исследуем proto разными способами:

Литерал объекта с использованием методов object.create и object.setPrototypeOf

1. с помощью object.create: **

Итак, у нас есть объект Car с тремя свойствами или методами и больше ничего. Затем мы объявили переменную tesla и присвоили ее объекту object.create с двумя параметрами, который является объектом Car, а второй параметр представляет собой объект со свойством name и значением tesla (это простой объект, но с другой формой определения внутри object.create), Давайте зарегистрируем переменную tesla и посмотрим, что делает object.create:

Как мы видим, object.create определяет объект со свойством name и значением tesla, используя второй параметр, и __proto__ этого объекта ссылается на объект, который мы указали в первом параметре object.create (в данном примере это объект Car) и прототип объекта Car относится к прототипу глобального объекта, а прототип глобального объекта относится к null.

цепочка прототипов объектов

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

вторая переменная, которую мы определили, — это detail, давайте просто зарегистрируем ее:

Это объект со своим особым свойством, называемым скоростью и значением 3001, и его прототип относится к tesla, как вы можете догадаться из примера изображения, а прототип tesla относится к объекту Car, а прототип объекта Car относится к глобальному прототипу объекта. и это цепочка прототипов.

Прототип делегации

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

поэтому, когда мы регистрируем tesla.speed, javascript будет искать его внутри объекта tesla, а если не найдет, он будет искать его внутри своего прототипа, который является объектом Car, и если такого свойства нет, он будет продолжать искать это внутри другого прототипа в цепочке прототипов, который является глобальным прототипом объекта, и если его там тоже нет, это даст нам неопределенность.

причина раздражающей ошибки, известной как «** не является функцией»

Как я объяснял выше, когда javascript не может найти свойство внутри цепочки прототипов, он возвращает значение undefined. Но если свойство скорости было функцией (методом), а не числом, и javascript не может его найти, он вернет ошибку «tesla.speed не является функцией».

поэтому, когда мы вызываем некоторые методы для массивов или функций, а javascript не может их найти, он возвращает ошибку, и я уверен, что вы были в той ситуации, когда раньше продолжали получать «* не является функцией».

третья переменная с именем volvo будет иметь тот же процесс, что и tesla, и разница между volvo и tesla заключается только в том, что значение свойства name равно volvo:

2. используя object.setPrototypeOf: **

три переменные (tesla,detail,volvo), которые мы определили выше, могут быть определены с помощью метода object.setPrototypeOf():

В этом случае мы определяем объект с его особым свойством и значением. Затем первый параметр object.setPrototypeOf выбирает объект, ссылкой на proto которого мы хотим манипулировать, а второй параметр — это объект, на который мы хотим ссылаться proto.

Таким образом, на приведенном выше изображении мы выбираем tesla и устанавливаем его прото-ссылку на объект Car, выбираем детальный объект и устанавливаем его прототип на объект tesla, а затем прото-объект volvo на объект Car.

Функция конструктора с использованием нового ключевого слова

Функции есть функция и объект!

Функции могут вести себя как объекты, потому что, когда мы их определяем, javascript предоставляет им кучу методов и свойств, и, как вы можете видеть, я определил функцию Car и дал ей свойство name.

Теперь давайте исследуем изображение выше:

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

В приведенном выше примере определение tesla с новым ключевым словом и функцией Car() и 'this.name' внутри функции Car выглядит примерно так: «Привет, javascript, у tesla должно быть свойство имени, и его значение должно быть тем, что передается в качестве аргумента, а также вольво».

Функция car называется Функция-конструктор.

Эй, мы пропустили эту часть прототипа, что насчет этого????🤔

В приведенном выше примере мы манипулируем прототипом объекта Car. Поэтому, когда Car становится ссылкой на прототип любого объекта, это будет объект, содержащий те методы, которые мы дали прототипу Car.

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

Давайте зарегистрируем tesla и посмотрим результат:

Когда мы создали экземпляр Car как tesla, мы создали объект со свойством name и значением tesla, а его прототип ссылается на прототип Car, который представляет собой объект с тремя определенными нами методами, и этот объект ссылается на прототип глобального объекта. тот же процесс верен и для volvo.

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

Теперь главная причина, почему у нас есть прототипы?

Представьте, что мы хотим объявить тысячи объектов со свойством name и некоторыми методами, которые должны быть у всех из них, и все эти методы делают то же самое, что и методы других объектов.
Как вы думаете, стоит ли объявить все эти объекты один за другим и определить все эти методы один за другим для каждого объекта? Конечно нет! это убьет память.

используя функцию-конструктор и прототипы, нам просто нужно объявить один объект со всеми необходимыми методами, и позволить другим объектам просто наследовать эти методы и использовать их.

в приведенном выше примере мы не объявляем объект volvo и объект tesla, и каждый из них имеет три метода, мы просто создаем экземпляр Car и наследуем от него методы.

обратите внимание, что ключевое слово this внутри метода sayName относится к объекту, который его наследует

обратите внимание, что в приведенном выше примере в последней строке мы регистрируем метод tesla.noneFunction, поэтому javascript будет искать его в своей цепочке прототипов и, если не найдет, вернет «tesla.noneFunctoin не является функцией».

и да! Прототип глобального объекта — это один объект-прототип, содержащий методы для всех объектов в javascript.

разница между __proto__ и прототипом

Мы зашли так далеко, я не собираюсь оставлять вас с этим вопросом без ответа. Хотя вы, возможно, уже заметили разницу.
Прототип просто существует в функции и определяется как свойство при объявлении функции. Прототип — это просто объект методов, которые мы передаем функции-конструктору в качестве ссылки на __proto__ его объекта-экземпляра.

как мы видим, Car.prototype — это тот же tesla.__proto__ , потому что tesla — это экземпляр Car, а его proto относится к Car.prototype.

__proto__ для объектов и прототип для функций.

Классы ES6, использующие новое ключевое слово

Теперь мы приближаемся к области ООП… Во многих языках программирования у нас есть концепция, называемая ООП или объектно-ориентированное программирование, которая является парадигмой разработки программ с использованием классов и объектов.
Классы представлены в ES6 и сделаны Javascript может использовать oop, но он просто имитирует его и делает похожим на oop, но внутри он совершенно другой, и javascript использует тот же процесс-прототип, о котором мы уже знали. Другими словами, в javascript есть oop, но по-своему :)

Теперь давайте посмотрим на процесс создания прототипа с классами и новым синтаксисом, чтобы лучше понять, как выглядит oop и как происходит процесс создания прототипа и наследования:

Я объявил класс Car, и внутри этого класса у нас есть конструктор. Это та же функция-конструктор, которую мы видели ранее:

И методы, которые мы объявили внутри класса Car, похожи на то, что мы установили прототип Car для некоторых методов, но более просто и понятно:

Теперь поговорим об этой части:

Что ж, вы уже знаете «новое» ключевое слово и то, что оно делает.

Он создает экземпляр Car и создает новый объект со свойством name и значением tesla, а также объект proto, который ссылается на объект, содержащий те три метода, которые мы объявили внутри класса Car, и еще один объект __proto__, который ссылается на прототип глобального объекта… то же самое для вольво.

Затем мы объявляем еще один класс, называемый Detail, с его специальным свойством, названным speed, и с помощью extends и super() мы наследуем все вещи внутри класса Car, включая свойство name и прото-объект трех методов.

Вот результат регистрации объекта подробностей, созданного из объекта Car:

Вот как javascript реализует oop :)

Мы узнали о прототипе, о том, что это такое и как вы можете использовать его различными способами в javascript.

В следующей части мы рассмотрим четыре столпа ООП и все, что нам нужно знать, на реальных примерах и примерах кода.

До следующей части, до свидания и удачи🤞