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

Одна важная вещь, которую нужно знать о JavaStript, заключается в том, что каждый созданный объект наследует свойства и методы от своего прототипа. Вы можете добавить к своему объекту объекты-прототипы, которые будут организованы в цепочку прототипов . В верхней части этой цепочки вы найдете Object.prototype, объект, который имеет такие свойства и методы, как: — .hasOwnProperty() и .toString() — к ним может получить доступ любой объект, что означает, что он является частью области действия объекта в JavaScript.

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

.toString() — возвращает строковое представление этого объекта.

Если вы хотите это проверить:

// to open the console on your browser type command + option + j
// inside the console type 
Object.prototype
// press enter

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

Как работает цепочка прототипов в javaScript?!

Допустим, вы создаете переменную obj, связанную с объектом:

var obj = { ‘a’: 2};
obj.toString()
// => ‘[object Object]’

Это работает следующим образом: интерпретатор заглянет внутрь этой области объекта и увидит, объявлен ли там метод .toString(), мы только что создали obj и просто передали ключ : 'a 'и значение: 2, поэтому интерпретатор не найдет этотметод.Поэтому интерпретатор поднимается на один уровень в цепочке в поисках этого конкретного метода, поскольку это простой объект, у него нет очень интересной цепочки прототипов, поэтому интерпретатор переходит из области видимости 'obj' в область Object.prototype, и там он найдет .toString(), возвращающий obj в виде строки вместо undefined.

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

Перво-наперво, давайте создадим объект вручную:

// create an empty object
const lara = {};
// now with the object we can assign properties and values to it
lara.firstName = ‘Lara’;
lara.lastName = ‘Ismael’
lara.age = 29;
lara.country = ‘Brasil’;
lara.sayName = (firstName, lastName) => console.log(`${ firstName } ${ lastName }`);

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

Так как же нам обойти это повторяющееся движение создания объектов???

— Введите экземпляры Объекта:

1- Функциональная реализация:

// create a function to instantiate different objects with the same structure
var peoplesInfo = (firstName, lastName, age, country) => {
  return {
    firstName: this.firstName, 
    lastName: this.lastName,   
    age: this.age,
    country: this. country,
    sayName: (firstName, LastName) => 
      console.log(`${ firstName } ${ LastName }`);
  }
}

Эта функция использует ключевое слово 'this', и я не буду вдаваться в подробности того, как она работает, но для понимания цели в этом случае 'this' привязано к аргументам, которые вы будете передавать при вызове функции.

Теперь это намного лучше, чем создание объекта нескольких людей… Помните, НЕ ПОВТОРЯЙТЕСЬ СЕБЯ.

// here we create 2 people using the function we created above
var Lara = peoplesInfo( ‘Lara’, ‘Ismael’, 29, ‘Brasil’); 
var Aly = peoplesInfo( ‘Aly’, ‘Smith’, 33, ‘USA’);

И вот мы только что решили проблему повторения…

Некоторые другие преимущества создания функциональных экземпляров заключаются в том, что у вас могут быть закрытые переменные, ЕСЛИ вы правильно используете свои функции закрытия. Это то, что предлагает только функциональная реализация. С другой стороны, здесь есть повторение, потому что каждый раз, когда мы создаем новый объект с помощью этой функции, мы создаем метод sayName().

2- Прототип:

// create a function to instantiate different objects with the same structure we use the create method
var peoplesInfo = (firstName, lastName, age, country) => {
  var result = Object.create( peoplesInfo.prototype);
  result .firstName = firstName;
  result .lastName = lastName;
  result .age = age;
  result .country = country;
  return result;
};
peoplesInfo.prototype.sayName: (firstName, lastName) =>
  console.log(`${ firstName } ${ lastName }`);
// now we can create people:
var Lara = new peoplesInfo( ‘Lara’, ‘Ismael’, 29, ‘Brasil’);
var Aly = new peoplesInfo( ‘Aly’, ‘Smith’, 33, ‘USA’);

Приведенный выше код работает следующим образом: переменная result может быть делегирована peoplesInfo.prototype и в случае поиска этого объекта, когда peoplesInfo должен возвращать undefined, результирующая переменная имеет метод sayName() в своей цепочке прототипов, поэтому интерпретатор сможет найти его и вместо возврата undefined он фактически сможет ссылаться на функцию и полное имя console.log.

Просто чтобы быть предельно ясным, когда вы вызываете peoplesInfo.sayName(), интерпретатор проверяет sayName внутри объекта peoplesInfo и не находит его, в этот момент он делегирует прототип подбородка, поиск sayName() и возврат его.

3- Псевдоклассическая реализация:

// create a function to instantiate different objects with the same structure and we can omit the create method
var peoplesInfo = (firstName, lastName, age, country) => {
  
  // no need for this anymore:
  /* var result = Object.create( peoplesInfo.prototype); */
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
  this.country = country;
  // no need for this anymore:
  /* return result; */
};
peoplesInfo.prototype.sayName: (firstName, lastName) =>
  console.log(`${ firstName } ${ lastName }`);
// now we can create people:
var Lara = new peoplesInfo( ‘Lara’, ‘Ismael’, 29, ‘Brasil’);
var Aly = new peoplesInfo( ‘Aly’, ‘Smith’, 33, ‘USA’);

Давайте начнем знакомство с ключевым словом new, которое устанавливает новый объект в соответствии со структурой, созданной в peoplesInfo(). peoplesInfo.prototype.sayName() — это то, что будет первым в цепочке прототипов, если вызов this не удался. примером этого может быть, когда мы вызываем this.sayName(), браузер будет искать в функции peoplesInfo sayName(), не найдя ее, интерпретатор перейдет к следующий объект-прототип в цепочке, и он находит его там и console.logs this.sayName().

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

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

Теперь давайте рассмотрим конкретный случай наследования с использованием псевдоклассики:

// create your class
var Person = function(name) {
  this.name = name;
};
// create a method for your class 
Person.prototype.travelPlaces = function(destination) {
  return `${this.name} is walking to ${destination}!`;
};
// create a subclass that inherits properties of Person class 
var FasterPerson = function(name, transportation) {
  // get all properties passed from Person
  Person.apply(this, arguments);
  // add the new properties specific to this subclass
  this.transportation = transportation;
};
//now we create the prototype chain connection
FasterPerson.prototype = Object.create(Person.prototype)
// make the subclass a constructor
FasterPerson.prototype.constructor = FasterPerson;
// at this point we can use the function that we inherited from Person and add some more functionality to it
FasterPerson.prototype.travelPlaces = function(destination, milesToDestination) {
  if (milesToDestination < 10) {
    return Person.prototype.travelPlaces.apply(this, arguments); 
  } else {
    return 
   `${this.name} using a ${transportation} is going to ${destination}!`;
  } 
};

Это все для этого поста…

Спасибо за прочтение, надеюсь было полезно!