Рубрики
Без рубрики

Все, что вам нужно знать, чтобы понять прототип JavaScript

Shirshendu Bhowmick большую часть времени прототип JavaScript смущает людей, которые только что начали изучать JavaScript – особенно если они с фона C ++ или Java. В JavaScript наследство работает немного по-разному по сравнению с C ++ или Java. Наследование JavaScript более широко известно как «прототипное наследство»

Автор оригинала: FreeCodeCamp Community Member.

Ширшендю Бхумик

В большинстве случаев прототип JavaScript смущает людей, которые только что начали изучать JavaScript – особенно если они с фона C ++ или Java.

В JavaScript наследство работает немного по-разному по сравнению с C ++ или Java. Наследование JavaScript более широко известно как «прототипное наследство».

Все становится сложнее понять, когда вы также столкнулись с Класс в JavaScript. Новый Класс Синтаксис выглядит похоже на C ++ или Java, но на самом деле он работает по-разному.

В этой статье мы постараемся понять «прототипов наследования» в JavaScript. Мы также смотрим в новый Класс На основании синтаксиса и попытайтесь понять, что это на самом деле. Так что давайте начнем.

Во-первых, мы начнем с функции road School JavaScript и прототипа.

Понимание необходимости прототипа

Если вы когда-либо работали с массивами или объектами или строками JavaScript, вы заметили, что по умолчанию есть пара методов, доступных по умолчанию.

Например:

var arr = [1,2,3,4];arr.reverse(); // returns [4,3,2,1]
var obj = {id: 1, value: "Some value"};obj.hasOwnProperty('id'); // returns true
var str = "Hello World";str.indexOf('W'); // returns 6

Вы когда-нибудь задумывались, откуда эти методы? Вы не определили эти методы самостоятельно.

Можете ли вы определить свои собственные методы такие? Вы могли бы сказать, что вы можете таким образом:

var arr = [1,2,3,4];arr.test = function() {    return 'Hi';}arr.test(); // will return 'Hi'

Это будет работать, но только для этой переменной называется arr Отказ Скажем, у нас есть другая переменная под названием Arr2 Тогда Arr2.test () Буду бросить ошибку «jueError: Arr2.test не является функцией».

Итак, как эти методы становятся доступными для каждого экземпляра массива/строки/объекта? Можете ли вы создать свои собственные методы с тем же поведением? Ответ да. Вы должны сделать это правильно. Чтобы помочь с этим, в приходит прототип JavaScript.

Давайте сначала посмотрим, откуда эти функции исходит. Рассмотрим фрагмент кода ниже:

var arr1 = [1,2,3,4];var arr2 = Array(1,2,3,4);

Мы создали два массива двумя разными способами: Arr1 с литералами массива и Arr2 с Массив Функция конструктора. Оба эквивалентны друг другу с некоторыми различиями, которые не имеют значения для этой статьи.

Теперь приходите к функции конструктора Массив – Это предопределенный конструктор функции в JavaScript. Если вы откроете инструменты Chrome Developer и перейдите в консоль и введите Console.log (Array.Prototype) и ударил Введите Вы увидите что-то вроде ниже:

Там вы увидите все методы, о которых нам было интересно. Так что теперь мы получаем от того, где приходят эти функции. Не стесняйтесь попробовать с String.Prototype и Объект. Прототип Отказ

Давайте создадим нашу собственную функцию конструктора:

var foo = function(name) { this.myName = name; this.tellMyName = function() {   console.log(this.myName); }}
var fooObj1 = new foo('James');fooObj1.tellMyName(); // will print Jamesvar fooObj2 = new foo('Mike');fooObj2.tellMyName(); // will print Mike

Можете ли вы определить фундаментальную проблему с вышеуказанным кодом? Проблема в том, что мы тратите память с приведенным выше подходом. Обратите внимание, что метод CultmyName одинаково для каждого экземпляра Foo Отказ Каждый раз, когда мы создаем экземпляр Foo Метод CultmyName заканчивается, принимая место в памяти системы. Если CultmyName То же самое для всех случаев, что лучше держать его в одном месте и сделать все наши экземпляры, относящиеся от этого места. Давайте посмотрим, как это сделать.

var foo = function(name) { this.myName = name;}
foo.prototype.tellMyName = function() {   console.log(this.myName);}
var fooObj1 = new foo('James');fooObj1.tellMyName(); // will print Jamesvar fooObj2 = new foo('Mike');fooObj2.tellMyName(); // will print Mike

Давайте проверим разницу с приведенным выше подходом и предыдущим подходом. С приведенным выше подходом, если вы Console.dir () Инстанции тогда вы увидите что-то вроде этого:

Обратите внимание, что как свойство экземпляров, у нас есть только MyName Отказ CultmyName определяется под __proto__ Отказ Я приду к этому __proto__ через некоторое время. Самое главное обратите внимание, что сравнение CultmyName обоих экземпляров оценивают правду. Сравнение функций в JavaScript оценивает true, только если их ссылки одинаковы. Это доказывает, что CultmyName не потребляет дополнительную память для нескольких экземпляров.

Давайте посмотрим то же самое с предыдущим подходом:

Обратите внимание, что на этот раз CultmyName определяется как свойство экземпляров. Это больше не под этим __proto__ Отказ Кроме того, отметьте, что на этот раз сравнивая функции, оценивают ложь. Это потому, что они находятся в двух разных местах памяти, и их ссылки разные.

Надеюсь, теперь вы понимаете необходимость Прототип Отказ

Теперь давайте посмотрим на более подробную информацию о прототипе.

Каждый и каждая функция JavaScript будет иметь Прототип Свойство, которое имеет тип объекта. Вы можете определить свои собственные свойства под Прототип Отказ Когда вы будете использовать функцию функции конструктора, все экземпляры оно наследуют свойства от Прототип объект.

Теперь давайте пришли к этому __proto__ Имущество, которое вы видели выше. __proto__ это просто ссылка на объект прототипа, из которого унаследовано экземпляр. Звучит сложно? Это на самом деле не так сложно. Давайте визуализируем это с примером.

Рассмотрим код ниже. Мы уже знаем, что создание массива с литералами массива наследует свойства от Array.Prototype Отказ

var arr = [1, 2, 3, 4];

То, что я только что сказал выше, это « __proto__ – это просто ссылка на объект прототипа, из которого экземпляр унаследовал ». Итак, ARR .__ Proto__ должно быть то же самое с Array.Prototype Отказ Давайте проверим это.

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

var arr = [1, 2, 3, 4];var prototypeOfArr = Object.getPrototypeOf(arr);prototypeOfArr === Array.prototype;prototypeOfArr === arr.__proto__;

Последняя строка из вышеуказанного фрагмента кода показывает, что __proto__ и Object.GetPrototyepef вернуть то же самое.

Теперь пришло время для перерыва. Возьмите кофе или что угодно, и попробуйте примеры выше самостоятельно. Как только вы будете готовы, вернитесь к этой статье, и мы продолжим.

Цепочка и наследование прототипов

На фиг.: 2 выше, вы заметили, что есть еще один __proto__ Внутри первого __proto__ объект? Если не прокрутите немного до фиг.: 2. Посмотрите и вернитесь здесь. Теперь мы обсудим то, что это на самом деле. Это известно как цепочка прототипа.

В JavaScript мы достигаем наследства с помощью цепочки прототипа.

Рассмотрим этот пример: мы все понимаем термин «транспортное средство». Автобус можно назвать автомобилем. Автомобиль можно назвать автомобилем. Мотоцикл можно назвать автомобилем. Автобус, автомобиль и мотоцикл имеют некоторые общие свойства, поэтому они называются автомобилем. Например, они могут двигаться из одного места в другое. У них есть колеса. У них рога и т. Д.

Опять автобус, автомобиль и мотоцикл могут быть разных типов, например Mercedes, BMW, Honda и т. Д.

На иллюстрации выше, автобус наследует некоторую недвижимость от автомобиля, а Mercedes Benz Bus наследует недвижимость с автобуса. Аналогичный случай для автомобиля и мотоцикла.

Давайте установим эти отношения в JavaScript.

Во-первых, давайте предположим несколько очков ради простоты:

  1. Все автобусы имеют 6 колес
  2. Ускоряющиеся и тормозные процедуры различны на автобусах, автомобилях и мотоциклах, а то же самое во всех автобусах, всех автомобилях и всех мотоциклах.
  3. Все автомобили могут взорвать рог.
function Vehicle(vehicleType) {  //Vehicle Constructor    this.vehicleType = vehicleType;}
Vehicle.prototype.blowHorn = function () {    console.log('Honk! Honk! Honk!'); // All Vehicle can blow Horn}
function Bus(make) { // Bus Constructor  Vehicle.call(this, "Bus");      this.make = make}
Bus.prototype = Object.create(Vehicle.prototype); // Make Bus constructor inherit properties from Vehicle Prototype Object
Bus.prototype.noOfWheels = 6; // Let's assume all buses have 6 wheels
Bus.prototype.accelerator = function() {    console.log('Accelerating Bus'); //Bus accelerator}
Bus.prototype.brake = function() {    console.log('Braking Bus'); // Bus brake}
function Car(make) {  Vehicle.call(this, "Car");  this.make = make;}
Car.prototype = Object.create(Vehicle.prototype);
Car.prototype.noOfWheels = 4;
Car.prototype.accelerator = function() {    console.log('Accelerating Car');}
Car.prototype.brake = function() {    console.log('Braking Car');}
function MotorBike(make) {  Vehicle.call(this, "MotorBike");  this.make = make;}
MotorBike.prototype = Object.create(Vehicle.prototype);
MotorBike.prototype.noOfWheels = 2;
MotorBike.prototype.accelerator = function() {    console.log('Accelerating MotorBike');}
MotorBike.prototype.brake = function() {    console.log('Braking MotorBike');}
var myBus = new Bus('Mercedes');var myCar = new Car('BMW');var myMotorBike = new MotorBike('Honda');

Позвольте мне объяснить вышеуказанный фрагмент кода.

У нас есть Автомобиль Конструктор, который ожидает типа транспортного средства. Как все машины могут взорвать их рога, у нас есть Breathorn Недвижимость в Автомобиль прототип.

Как Автобус это транспортное средство, которое он наследует свойства от Автомобиль объект.

Мы предполагали, что все автобусы будут иметь 6 колес и имеют одинаковые ускоренные и тормозные процедуры. Так что у нас есть noofwheels , Ускоритель и Тормоз Имущество, определенное в Автобус прототип.

Подобная логика применяется для автомобиля и мотоциклов.

Пойдем до инструментов Chrome Developer -> Console и выполните наш код.

После выполнения у нас будет 3 объекта Mybus , MyCar и MyMotorbike Отказ

Тип console.dir (mybus) В консоли и ударить Введите Отказ Используйте значок треугольника, чтобы расширить его, и вы увидите что-то вроде ниже:

Под Mybus У нас есть свойства сделать и Vehicletype Отказ Обратите внимание на ценность __proto__ это прототип Автобус Отказ Все свойства его прототипа доступны здесь: Ускоритель , Тормоз , noofwheels Отказ

Теперь посмотрите, что первый __proto__ объект. Этот объект имеет еще один __proto__ объект как его собственность.

При котором у нас есть Breathorn и Конструктор имущество.

Bus.prototype = Object.create(Vehicle.prototype);

Помните линию выше? Object.Create (автомобиль. Прототип) создаст пустой объект, прототип которого является Автомобиль. Прототип Отказ Мы устанавливаем этот объект как прототип Автобус Отказ Для Автомобиль. Прототип Мы не указали никакого прототипа, так что по умолчанию он наследует от Объект. Прототип Отказ

Давайте посмотрим на магию ниже:

Мы можем получить доступ к сделать недвижимость как это Mybus собственная собственность.

Мы можем получить доступ к Тормоз Недвижимость от Mybus прототип.

Мы можем получить доступ к Breathorn Недвижимость от Mybus прототип прототипа.

Мы можем получить доступ к HasownProperty Недвижимость от Mybus прототип прототипа прототипа.:)

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

Так сколько времени это проведет таким образом? Он остановится, если свойство найдено в любой точке или если значение __proto__ В любой момент – null или undefined Отказ Затем он бросит ошибку, чтобы уведомить вас, что не удалось найти свойство, которое вы искали.

Вот как наследование работает в JavaScript с помощью цепочки прототипа.

Не стесняйтесь попробовать вышеприведенный пример с MyCar и MyMotorbike Отказ

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

Исключение для вышеуказанного правила – если вы создаете объект с Object.Create (NULL)

var obj = Object.create(null)

С вышеуказанным кодом obj Будет пустой объект без какого-либо прототипа.

Для получения дополнительной информации о Object.Create Проверьте документацию на MDN.

Можете ли вы изменить объект прототипа существующего объекта? Да, с Object.SetPrototyepef () ты можешь. Проверьте документацию в MDN.

Хотите проверить, является ли недвижимость собственной собственностью объекта? Вы уже знаете, как это сделать. Объект. HasownProperty Скажу вам, если имущество исходит от самого объекта или из его цепочки прототипа. Проверьте его документацию на MDN.

Обратите внимание, что __proto__ Также упоминается как [[Прототип]] Отказ

Теперь пришло время для другого перерыва. Как только вы будете готовы, вернитесь к этой статье. Затем мы продолжим, и я обещаю, это последняя часть.

Понимание классов в JavaScript

По данным MDN:

Классы в JavaScript обеспечит лучший синтаксис для достижения того, что мы сделали выше гораздо более чистого способа. Давайте сначала посмотрите в синтаксис класса.

class Myclass {  constructor(name) {    this.name = name;  }    tellMyName() {    console.log(this.name)  }}
const myObj = new Myclass("John");

Конструктор Метод является специальным типом способа. Он будет автоматически выполнен, когда вы создаете экземпляр этого класса. Внутри вашего класса тела. Только одно вхождение Конструктор возможно.

Методы, которые вы определите внутри корпуса класса, будут перемещены в объект прототипа.

Если вы хотите недвижимость внутри экземпляра, вы можете определить его в конструкторе, так как мы сделали с Это. Немайте Отказ

Давайте посмотрим на наш Myobj Отказ

Обратите внимание, что у нас есть Имя Свойство внутри экземпляра, который является Myobj и метод CultmyName находится в прототипе.

Рассмотрим фрагмент кода ниже:

class Myclass {  constructor(firstName) {    this.name = firstName;  }    tellMyName() {    console.log(this.name)  }  lastName = "lewis";}
const myObj = new Myclass("John");

Давайте посмотрим на вывод:

Увидеть это фамилия перемещается в экземпляр вместо прототипа. Только методы, которые вы, которые вы объявляете внутри класса, будет перемещен в прототип. Есть исключение, хотя.

Рассмотрим фрагмент кода ниже:

class Myclass {  constructor(firstName) {    this.name = firstName;  }    tellMyName = () => {    console.log(this.name)  }  lastName = "lewis";}
const myObj = new Myclass("John");

Выход:

Обратите внимание, что CultmyName Сейчас является функцией стрелки, и она была перемещена в экземпляр вместо прототипа. Так что помните, что функции стрелки всегда будут перемещены в экземпляр, поэтому используйте их тщательно.

Давайте рассмотрим свойства статического класса:

class Myclass {  static welcome() {    console.log("Hello World");  }}
Myclass.welcome();const myObj = new Myclass();myObj.welcome();

Выход:

Статические свойства – это то, что вы можете получить доступ без создания экземпляра класса. С другой стороны, экземпляр не будет иметь доступа к статическим свойствам класса.

Так что статическое свойство новая концепция, которая доступна только с классом, а не в старой школе JavaScript? Нет, это там в ard School JavaScript также. Старый школьный метод достижения статического свойства:

function Myclass() {}Myclass.welcome = function() {  console.log("Hello World");}

Теперь давайте посмотрим, как мы можем достичь наследства с классами.

class Vehicle {  constructor(type) {    this.vehicleType= type;  }  blowHorn() {    console.log("Honk! Honk! Honk!");  }}
class Bus extends Vehicle {  constructor(make) {    super("Bus");    this.make = make;   }  accelerator() {    console.log('Accelerating Bus');  }  brake() {    console.log('Braking Bus');  }}
Bus.prototype.noOfWheels = 6;
const myBus = new Bus("Mercedes");

Мы наследуем другие классы, используя расширяется ключевое слово.

Super () будет просто выполнить конструктор родительского класса. Если вы унаследовали от других классов, и вы используете конструктор в своем детском классе, то вам нужно позвонить Super () Внутри конструктора вашего дочернего класса в противном случае он бросит ошибку.

Мы уже знаем, что если мы определим любое свойство, кроме нормальной функции в корпусе класса, она будет перемещена в экземпляр вместо прототипа. Итак, мы определяем Noofwheel на Шина. Прототип Отказ

Внутри вашего класса, если вы хотите выполнить метод родительского класса, вы можете сделать это, используя Super.ParentClassMethod () Отказ

Выход:

Вышеуказанный выход выглядит похоже на наш предыдущий подход на основе функций на фиг.: 7.

Обертывание

Так что вы должны использовать новый синтаксис класса или синтаксис на основе старого конструктора? Я думаю, что нет определенного ответа на этот вопрос. Это зависит от вашего случая использования.

В этой статье для классов, которую я только что продемонстрировал, как вы сможете достичь прототипических классов наследования. Подробнее узнать о классах JavaScript, но это выходит из объема этой статьи. Проверьте документацию классов на MDN. Или я постараюсь написать всю статью на классы в какое-то время.

Если эта статья помогла вам в понимании прототипов, я был бы признателен, если бы вы могли аплодировать немного.

Если вы хотите, чтобы я написал на какой-то другой теме, дайте мне знать в ответах.

Вы также можете связаться со мной через LinkedIn Отказ

Спасибо за чтение.:)