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

function sayHello () {return «Hello World»};
sayHello.prototype

мы увидим что-то вроде этого:

{конструктор: f}

Это означает, что это объект, когда мы откроем {constructor: f}, мы увидим еще один объект __proto__, и каждый объект имеет это скрытое свойство, которое выглядит примерно так:

__proto__: {// некоторые методы и функции}

Есть 4 способа делать классы.

1: - Заводской класс
2: - На основе прототипа (псевдоклассический шаблон)
3: - Конструктор классов

1: - Заводской класс

Функция factory - это функция, возвращающая (предположительно новый) объект. В JavaScript любая функция может возвращать объект. Когда это происходит без ключевого слова new, это заводская функция. для лучшего понимания см. пример ниже:

function createAnimal(name, age) {
  let animal = Object.create({});
  animal.name = name;
  animal.age = age;
  return animal;
}
let dog = createAnimal('Dog', 15);
console.log(dog);

здесь мы создаем функцию с именем createAnimal и передаем в нее два параметра name и age. теперь, когда мы вызываем функцию, создается локальный контекст выполнения. внутри этого локального контекста выполнения будет создана локальная память (в ней хранятся все переменные области действия функции), где она увидит, что существует переменная (имя которой животное), потому что мы используем Object.create () с пустым ({}) объектом. так что теперь animal будет Object, теперь мы назначаем имя свойства и возраст, а затем мы возвращаем Object (animal), теперь значение возвращается и сохраняется в переменной dog (контекст выполнения удаляется, когда функция что-то возвращает).

2: - На основе прототипа (Псевдоклассический шаблон)

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

function CreateAnimal(name, age) {
  this.name = name;
  this.age = age;
}
var dog = new CreateAnimal('dog', 10);
console.log(dog);
// CreateAnimal {name: 'dog', age: 10}

мы создали функцию CreateAnimal, которая принимает два параметра: имя и возраст. Когда мы вызываем функцию с ключевым словом new, она создает новый пустой объект, затем мы передаем аргумент dog и 10 .Теперь, как мы знаем, когда функция вызывается, создается локальное выполнение. внутри контекста выполнения будет локальная память, внутри локальной памяти будет храниться name = dog и age = 10, и он вернет объект с переменной name и dog в качестве ключа объекта и dog и 10 как значение, и оно будет сохранено в объекте dog. теперь контекст выполнения будет удален.
Теперь, как установить метод в объекте с помощью прототипа.

CreateAnimal.prototype.eat = function() {
  return `${this.name} eats`;
}
CreateAnimal.prototype.move = function() {
  return `${this.name} moves`;
}

мы берем имя нашей функции CreateAnimal и получаем доступ к прототипу с помощью точки (потому что функция - это объект в javascript, а прототип - это свойство функции), и теперь мы устанавливаем свойство 'eat', значение которого является функцией, теперь переходим внутрь метода eat (функция ), и мы видим this.name здесь, это относится к экземпляру Object, который создается с использованием ключевого слова new, и при следующем перемещении функции мы делаем то же самое.

var cat = new CreateAnimal('Poo', 5)
console.log(cat)

мы создаем новый объект cat. когда мы консольным образом регистрируем наш объект cat, он собирается вернуть объект с именем, возрастом и его значениями, но подождите, когда мы увидим внутри нашего объекта другой объект __proto__ (это скрытое свойство объекта) и внутри прототипа есть наш метод eat and move со своим значением (функцией), потому что прототип создает связь между функцией и объектом.

Теперь мы хотим создать новую категорию, состоящую только из травоядных животных, которая также будет иметь некоторые особые свойства, например, они едят траву и т. Д.

function CreateHerbivores(name, age) {
  this.name = name;
  this.age = age;
}

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

CreateHerbivores.prototype.__proto__ = CreateAnimal.prototype;

вот что происходит? у нас есть функция CreateHerbivores, у которой есть прототип свойства (это объект), теперь мы получаем доступ к __proto__ (скрытое свойство каждого объекта) и назначаем прототипу функции CreateAnimal. теперь это создаст связь между этими двумя функциями. теперь мы можем получить доступ к свойству функции CreateAnimal.

давайте создадим новый объект:

var cow = new CreateHerbivores('Cow', 20);
console.log(cow);

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

cow.eat()

он вернет «Корова ест». то, что здесь происходит, он проверит, есть ли какое-либо свойство с именем eat в Object cow, которое он найдет здесь, поэтому он будет связан, а в CreateAnimal есть свойство eat, поэтому оно вернет значение функции.

Псевдоклассический узор

Он работает так же, как класс на основе прототипа, в псевдоклассическом шаблоне мы создаем экземпляр объекта с помощью ключевого слова new. есть только одно различие между псевдоклассическим шаблоном и классом связи на основе прототипа. в классе на основе прототипов мы меняем объект __proto__ функции CreateHerbivores на прототип функции CreateAnimal. а здесь, в Псевдоклассическом шаблоне, мы будем использовать call () * для создания связи. также мы можем использовать это:

CreateHerbivores.prototype .__ proto__ = Object.create (CreateAnimal.prototype);

мы также можем использовать этот код для создания связи между __proto__ функции CreateHerbivores и функцией CreateAnimal.

Примечание: - * Метод call() вызывает функцию с заданным значением this и аргументами, предоставленными индивидуально.
ссылка: - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call

В приведенном выше примере мы сделаем это псевдоклассическим способом.

function CreateAnimal(name, age) {
  this.name = name;
  this.age = age;
}

мы создаем функцию CreateAnimal, которая принимает два параметра: имя и возраст (здесь this - это экземпляр объекта). теперь мы хотим добавить новое свойство функции CreateAnimal eat и move.

CreateAnimal.prototype.eat = function() {
  return `${this.name} eats`;
}
CreateAnimal.prototype.move = function() {
  return `${this.name} moves`;
}

он установит эти методы, которые будут питаться и перемещаться внутри прототипа функции CreateAnimal. теперь мы создадим новую функцию.

function CreateHerbivores(name, age) {
  CreateAnimal.call(this, name, age);
}
CreateHerbivores.prototype.__proto__ = CreateAnimal.prototype;
CreateHerbivores.prototype.eatGrass = function() {
  return `${this.name} eats grass`;
}
let rabbit = new CreateHerbivores("Rabbit", 20);
console.log(rabbit);

в этой функции мы вызываем родительскую функцию (CreateAnimal) с помощью метода call () и внутри CreateAnimal.call (this, name, age); это будет относиться к экземпляру CreateAnimal. CreateHerbivores.prototype .__ proto__ = CreateAnimal.prototype; в этой строке мы создаем связь. затем мы делаем метод eatGrass в функции CreateHerbivores. когда мы запустим этот код. мы увидим что-то вроде этого: -

теперь мы можем получить доступ к свойству из его родительской функции CreateAnimal из-за связи.

3: - Конструктор классов

Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом.

class CreateAnimal {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  eat() {
    return `${this.name} eats`;
  } 
  move() {
    return `${this.name} moves`;
  }
}

в этом шаблоне мы используем ключевое слово «class» для определения функции, а в «конструкторе» мы передаем параметры, здесь, в нашей функции CreateAnimal, мы передаем два параметра: имя и возраст, а в следующей строке мы присваиваем значение с этим (здесь это относится к экземпляру объекта, который создается с использованием ключевого слова new). и мы заставляем две функции есть и двигаться. теперь мы создадим новый класс и свяжемся с функцией CreateAnimal.

class CreateHerbivores extends CreateAnimal{
  constructor(name, age) {
     super(name, age);
  }
  eatGrass() {
      return `${this.name} eats grass`;
  } 
}

здесь extends наследует свойство своего родителя, поэтому CreateHerbivores унаследует свойство CreateAnimal. Здесь ключевое слово super () используется для вызова методов родительского класса, и мы делаем функцию eatGrass.

Теперь мы создадим новый экземпляр Object.

let rabbit = new CreateHerbivores("Rabbit", 20);
console.log(rabbit)

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

он войдет в объект CreateHerbivores и будет искать функцию перемещения, он найдет ее внутри объекта, затем войдет внутрь __proto__ и будет искать его, если его нет здесь, он войдет в связь функции CreateAnimal и вернет Значение. что, если нет метода с именем move, он вернет undefined.