From 149b599368b4e27cf7d05f270a43519f599372fd Mon Sep 17 00:00:00 2001 From: MDN Date: Tue, 18 Jan 2022 00:57:02 +0000 Subject: [CRON] sync translated content --- .../objects/classes_in_javascript/index.html | 267 +++++++++++++++++++ .../javascript/objects/inheritance/index.html | 267 ------------------- .../objects/object-oriented_js/index.html | 287 --------------------- 3 files changed, 267 insertions(+), 554 deletions(-) create mode 100644 files/ru/learn/javascript/objects/classes_in_javascript/index.html delete mode 100644 files/ru/learn/javascript/objects/inheritance/index.html delete mode 100644 files/ru/learn/javascript/objects/object-oriented_js/index.html (limited to 'files/ru/learn') diff --git a/files/ru/learn/javascript/objects/classes_in_javascript/index.html b/files/ru/learn/javascript/objects/classes_in_javascript/index.html new file mode 100644 index 0000000000..ec27663266 --- /dev/null +++ b/files/ru/learn/javascript/objects/classes_in_javascript/index.html @@ -0,0 +1,267 @@ +--- +title: Наследование в JavaScript +slug: Learn/JavaScript/Objects/Classes_in_JavaScript +tags: + - JavaScript + - Наследование + - ООП +translation_of: Learn/JavaScript/Objects/Inheritance +original_slug: Learn/JavaScript/Objects/Inheritance +--- +

+ +

+ + + +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}
+ +

Теперь, когда объясняется большая часть подробностей OOJS, эта статья показывает, как создавать «дочерние» классы объектов (конструкторы), которые наследуют признаки из своих «родительских» классов. Кроме того, мы дадим некоторые советы о том, когда и где вы можете использовать OOJS , и посмотрим, как классы рассматриваются в современном синтаксисе ECMAScript.

+ + + + + + + + + + + + +
Необходимые знания: +

Базовая компьютерная грамотность, понимание основ HTML и CSS, знакомство с основами JavaScript (см. Первые шаги и Структурные элементы) and основы Объектно-ориентированного JS (см. Введение в объекты).

+
Цель:Понять, как можно реализовать наследование в JavaScript.
+ +

Прототипное наследование

+ +

До сих пор мы видели некоторое наследование в действии - мы видели, как работают прототипы и как элементы наследуются, поднимаясь по цепочке. Но в основном это связано с встроенными функциями браузера. Как создать объект в JavaScript, который наследует от другого объекта?

+ +

Давайте рассмотрим, как это сделать на конкретном примере.

+ +

Начало работы

+ +

Прежде всего сделайте себе локальную копию нашего файла oojs-class-inheritance-start.html (он также работает в режиме реального времени). В файле вы найдёте тот же пример конструктора Person(), который мы использовали на протяжении всего модуля, с небольшим отличием - мы определили внутри конструктора только лишь свойства:

+ +
function Person(first, last, age, gender, interests) {
+  this.name = {
+    first,
+    last
+  };
+  this.age = age;
+  this.gender = gender;
+  this.interests = interests;
+};
+ +

Все методы определены в прототипе конструктора. Например:

+ +
Person.prototype.greeting = function() {
+  alert('Hi! I\'m ' + this.name.first + '.');
+};
+ +
+

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

+
+ +

Скажем так, мы хотели создать класс Teacher, подобный тому, который мы описали в нашем первоначальном объектно-ориентированном определении, которое наследует всех членов от Person, но также включает в себя:

+ +
    +
  1. Новое свойство, subject - оно будет содержать предмет, который преподаёт учитель.
  2. +
  3. Обновлённый метод greeting(), который звучит немного более формально, чем стандартный метод greeting()— более подходит для учителя, обращающегося к некоторым ученикам в школе.
  4. +
+ +

Определение функции-конструктора Teacher()

+ +

Первое, что нам нужно сделать, это создать конструктор Teacher() - добавьте ниже следующий код:

+ +
function Teacher(first, last, age, gender, interests, subject) {
+  Person.call(this, first, last, age, gender, interests);
+
+  this.subject = subject;
+}
+ +

Это похоже на конструктор Person во многих отношениях, но здесь есть что-то странное, что мы не видели раньше - функцию call(). Эта функция в основном позволяет вам вызывать функцию, определённую где-то в другом месте, но в текущем контексте. Первый параметр указывает значение this, которое вы хотите использовать при выполнении функции, а остальные параметры - те, которые должны быть переданы функции при её вызове.

+ +

Мы хотим, чтобы конструктор Teacher() принимал те же параметры, что и конструктор Person(), от которого он наследуется, поэтому мы указываем их как параметры в вызове call().

+ +

Последняя строка внутри конструктора просто определяет новое свойство subject, которое будут иметь учителя, и которого нет у Person().

+ +

В качестве примечания мы могли бы просто сделать это:

+ +
function Teacher(first, last, age, gender, interests, subject) {
+  this.name = {
+    first,
+    last
+  };
+  this.age = age;
+  this.gender = gender;
+  this.interests = interests;
+  this.subject = subject;
+}
+ +

Но это просто переопределяет свойства заново, а не наследует их от Person(), так что теряется смысл того, что мы пытаемся сделать. Он также занимает больше строк кода.

+ +

Наследование от конструктора без параметров

+ +

Обратите внимание, что если конструктор, от которого вы наследуете, не принимает значения своего свойства из параметров, вам не нужно указывать их в качестве дополнительных аргументов в call(). Так, например, если у вас было что-то действительно простое:

+ +
function Brick() {
+  this.width = 10;
+  this.height = 20;
+}
+ +

Вы можете наследовать свойства width и height, выполнив это (как и другие шаги, описанные ниже, конечно):

+ +
function BlueGlassBrick() {
+  Brick.call(this);
+
+  this.opacity = 0.5;
+  this.color = 'blue';
+}
+ +

Обратите внимание, что мы указали только this внутри call() - никаких других параметров не требуется, поскольку мы не наследуем никаких свойств родителя, которые задаются через параметры.

+ +

Установка Teacher()'s prototype и конструктор ссылок

+ +

Пока все хорошо, но у нас есть проблема. Мы определили новый конструктор и у него есть свойство prototype, которое по умолчанию просто содержит ссылку на саму конструкторскую функцию. Он не содержит методов свойства prototype конструктора Person. Чтобы увидеть это, введите Object.getOwnPropertyNames(Teacher.prototype) в поле ввода текста или в вашу консоль JavaScript. Затем введите его снова, заменив Teacher на Person. Новый конструктор не наследует эти методы. Чтобы увидеть это, сравните выводы в консоль Person.prototype.greeting и Teacher.prototype.greeting. Нам нужно заставить Teacher() наследовать методы, определённые на прототипе Person(). Итак, как мы это делаем?

+ +
    +
  1. Добавьте следующую строку ниже своего предыдущего добавления: +
    Teacher.prototype = Object.create(Person.prototype);
    + Здесь наш друг create() снова приходит на помощь. В этом случае мы используем его для создания нового объекта и делаем его значением Teacher.prototype. Новый объект имеет свой прототип Person.prototype и, следовательно, наследует, если и когда это необходимо, все доступные методы Person.prototype.
  2. +
  3. Нам нужно сделать ещё одну вещь, прежде чем двигаться дальше. После добавления последней строки, Teacher.prototype.constructor стало равным Person(), потому что мы просто устанавливаем Teacher.prototype для ссылки на объект, который наследует его свойства от Person.prototype! Попробуйте сохранить код, загрузите страницу в браузере и введите Teacher.prototype.constructor в консоль для проверки.
  4. +
  5. Это может стать проблемой, поэтому нам нужно сделать это правильно. Вы можете сделать это, вернувшись к исходному коду и добавив следующие строки внизу: +
    Object.defineProperty(Teacher.prototype, 'constructor', {
    +    value: Teacher,
    +    enumerable: false, // false, чтобы данное свойство не появлялось в цикле for in
    +    writable: true });
    +
  6. +
  7. Теперь, если вы сохраните и обновите, введите Teacher.prototype.constructor, чтобы вернуть Teacher(), плюс мы теперь наследуем Person()!
  8. +
+ +

Предоставление Teacher() новой функции greeting()

+ +

Чтобы завершить наш код, нам нужно определить новую функцию greeting() в конструкторе Teacher().

+ +

Самый простой способ сделать это - определить его на прототипе Teacher() - добавить в нижнюю часть кода следующее:

+ +
Teacher.prototype.greeting = function() {
+  var prefix;
+
+  if (this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') {
+    prefix = 'Mr.';
+  } else if (this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') {
+    prefix = 'Mrs.';
+  } else {
+    prefix = 'Mx.';
+  }
+
+  alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.');
+};
+ +

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

+ +

Попробуйте пример

+ +

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

+ +
var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');
+ +

Теперь сохраните, обновите, и попробуйте получить доступ к свойствам и методам вашего нового объекта teacher1, например:

+ +
teacher1.name.first;
+teacher1.interests[0];
+teacher1.bio();
+teacher1.subject;
+teacher1.greeting();
+teacher1.farewell();
+ +

Все должно работать нормально. Запросы в строках 1, 2, 3 и 6 унаследованные от общего конструктора Person() (класса). Запрос в строке 4 обращается к subject, доступному только для более специализированного конструктора (класса) Teacher(). Запрос в строке 5 получил бы доступ к методу greeting(), унаследованному от Person(), но Teacher() имеет свой собственный метод greeting() с тем же именем, поэтому запрос обращается к этому методу.

+ +
+

Примечание. Если вам не удаётся заставить это работать, сравните свой код с нашей готовой версией (см. также рабочее демо).

+
+ +

Методика, которую мы здесь рассмотрели, - это не единственный способ создания наследующих классов в JavaScript, но он работает нормально и это даёт вам представление о том, как реализовать наследование в JavaScript.

+ +

Вам также может быть интересно узнать некоторые из новых функций {{glossary("ECMAScript")}}, которые позволяют нам делать наследование более чисто в JavaScript (см. Classes). Мы не рассматривали их здесь, поскольку они пока не поддерживаются очень широко в браузерах. Все остальные конструкторы кода, которые мы обсуждали в этом наборе статей, поддерживаются ещё в IE9 или ранее и есть способы добиться более ранней поддержки, чем это.

+ +

Обычный способ - использовать библиотеку JavaScript - большинство популярных опций имеют простой набор функций, доступных для выполнения наследования более легко и быстро. CoffeeScript , например, предоставляет класс, расширяет и т.д.

+ +

Дальнейшее упражнение

+ +

В нашем руководстве по Объектно-ориентированному JavaScript для начинающих мы также включили класс Student как концепцию, которая наследует все особенности Person, а также имеет другой метод greeting() от Person, который гораздо более неформален, чем приветствие Teacher. Посмотрите, как выглядит приветствие ученика в этом разделе, и попробуйте реализовать собственный конструктор Student(), который наследует все функции Person() и реализует другую функцию greeting().

+ +
+

Примечание. Если вам не удаётся заставить это работать, сравните свой код с нашей готовой версией (см. также рабочее демо).

+
+ +

Object member summary

+ +

Подводя итог, вы в основном получили три типа свойств / методов, о которых нужно беспокоиться:

+ +
    +
  1. Те, которые определены внутри функции-конструктора, которые присваиваются экземплярам объекта. Их довольно легко заметить - в вашем собственном коде они представляют собой элементы, определённые внутри конструктора, используя строки this.x = x; в встроенном коде браузера они являются членами, доступными только для экземпляров объектов (обычно создаются путём вызова конструктора с использованием ключевого слова new, например var myInstance = new myConstructor ().
  2. +
  3. Те, которые определяются непосредственно самим конструктором, которые доступны только для конструктора. Они обычно доступны только для встроенных объектов браузера и распознаются путём непосредственной привязки к конструктору, а не к экземпляру. Например, Object.keys().
  4. +
  5. Те, которые определены в прототипе конструктора, которые наследуются всеми экземплярами и наследуют классы объектов. К ним относятся любой член, определённый в свойстве прототипа конструктора, например. myConstructor.prototype.x().
  6. +
+ +

Если вы не уверены, что это такое, не беспокойтесь об этом, пока вы ещё учитесь и знание придёт с практикой.

+ +

Когда вы используете наследование в JavaScript?

+ +

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

+ +

В некотором смысле вы используете наследование все время. Всякий раз, когда вы используете различные функции веб-API или методы/свойства, определённые во встроенном объекте браузера, который вы вызываете в своих строках, массивах и т.д., вы неявно используете наследование.

+ +

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

+ +
+

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

+
+ +

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

+ +

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

+ +

Резюме

+ +

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

+ +

В следующей статье мы рассмотрим, как работать с JavaScript Object Notation (JSON), общим форматом обмена данными, написанным с использованием объектов JavaScript.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}

+ +

В этом модуле

+ + diff --git a/files/ru/learn/javascript/objects/inheritance/index.html b/files/ru/learn/javascript/objects/inheritance/index.html deleted file mode 100644 index f1514a92c6..0000000000 --- a/files/ru/learn/javascript/objects/inheritance/index.html +++ /dev/null @@ -1,267 +0,0 @@ ---- -title: Наследование в JavaScript -slug: Learn/JavaScript/Objects/Inheritance -tags: - - JavaScript - - Наследование - - ООП -translation_of: Learn/JavaScript/Objects/Inheritance -original_slug: Learn/JavaScript/Объекты/Inheritance ---- -

- -

- - - -
{{LearnSidebar}}
- -
{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}
- -

Теперь, когда объясняется большая часть подробностей OOJS, эта статья показывает, как создавать «дочерние» классы объектов (конструкторы), которые наследуют признаки из своих «родительских» классов. Кроме того, мы дадим некоторые советы о том, когда и где вы можете использовать OOJS , и посмотрим, как классы рассматриваются в современном синтаксисе ECMAScript.

- - - - - - - - - - - - -
Необходимые знания: -

Базовая компьютерная грамотность, понимание основ HTML и CSS, знакомство с основами JavaScript (см. Первые шаги и Структурные элементы) and основы Объектно-ориентированного JS (см. Введение в объекты).

-
Цель:Понять, как можно реализовать наследование в JavaScript.
- -

Прототипное наследование

- -

До сих пор мы видели некоторое наследование в действии - мы видели, как работают прототипы и как элементы наследуются, поднимаясь по цепочке. Но в основном это связано с встроенными функциями браузера. Как создать объект в JavaScript, который наследует от другого объекта?

- -

Давайте рассмотрим, как это сделать на конкретном примере.

- -

Начало работы

- -

Прежде всего сделайте себе локальную копию нашего файла oojs-class-inheritance-start.html (он также работает в режиме реального времени). В файле вы найдёте тот же пример конструктора Person(), который мы использовали на протяжении всего модуля, с небольшим отличием - мы определили внутри конструктора только лишь свойства:

- -
function Person(first, last, age, gender, interests) {
-  this.name = {
-    first,
-    last
-  };
-  this.age = age;
-  this.gender = gender;
-  this.interests = interests;
-};
- -

Все методы определены в прототипе конструктора. Например:

- -
Person.prototype.greeting = function() {
-  alert('Hi! I\'m ' + this.name.first + '.');
-};
- -
-

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

-
- -

Скажем так, мы хотели создать класс Teacher, подобный тому, который мы описали в нашем первоначальном объектно-ориентированном определении, которое наследует всех членов от Person, но также включает в себя:

- -
    -
  1. Новое свойство, subject - оно будет содержать предмет, который преподаёт учитель.
  2. -
  3. Обновлённый метод greeting(), который звучит немного более формально, чем стандартный метод greeting()— более подходит для учителя, обращающегося к некоторым ученикам в школе.
  4. -
- -

Определение функции-конструктора Teacher()

- -

Первое, что нам нужно сделать, это создать конструктор Teacher() - добавьте ниже следующий код:

- -
function Teacher(first, last, age, gender, interests, subject) {
-  Person.call(this, first, last, age, gender, interests);
-
-  this.subject = subject;
-}
- -

Это похоже на конструктор Person во многих отношениях, но здесь есть что-то странное, что мы не видели раньше - функцию call(). Эта функция в основном позволяет вам вызывать функцию, определённую где-то в другом месте, но в текущем контексте. Первый параметр указывает значение this, которое вы хотите использовать при выполнении функции, а остальные параметры - те, которые должны быть переданы функции при её вызове.

- -

Мы хотим, чтобы конструктор Teacher() принимал те же параметры, что и конструктор Person(), от которого он наследуется, поэтому мы указываем их как параметры в вызове call().

- -

Последняя строка внутри конструктора просто определяет новое свойство subject, которое будут иметь учителя, и которого нет у Person().

- -

В качестве примечания мы могли бы просто сделать это:

- -
function Teacher(first, last, age, gender, interests, subject) {
-  this.name = {
-    first,
-    last
-  };
-  this.age = age;
-  this.gender = gender;
-  this.interests = interests;
-  this.subject = subject;
-}
- -

Но это просто переопределяет свойства заново, а не наследует их от Person(), так что теряется смысл того, что мы пытаемся сделать. Он также занимает больше строк кода.

- -

Наследование от конструктора без параметров

- -

Обратите внимание, что если конструктор, от которого вы наследуете, не принимает значения своего свойства из параметров, вам не нужно указывать их в качестве дополнительных аргументов в call(). Так, например, если у вас было что-то действительно простое:

- -
function Brick() {
-  this.width = 10;
-  this.height = 20;
-}
- -

Вы можете наследовать свойства width и height, выполнив это (как и другие шаги, описанные ниже, конечно):

- -
function BlueGlassBrick() {
-  Brick.call(this);
-
-  this.opacity = 0.5;
-  this.color = 'blue';
-}
- -

Обратите внимание, что мы указали только this внутри call() - никаких других параметров не требуется, поскольку мы не наследуем никаких свойств родителя, которые задаются через параметры.

- -

Установка Teacher()'s prototype и конструктор ссылок

- -

Пока все хорошо, но у нас есть проблема. Мы определили новый конструктор и у него есть свойство prototype, которое по умолчанию просто содержит ссылку на саму конструкторскую функцию. Он не содержит методов свойства prototype конструктора Person. Чтобы увидеть это, введите Object.getOwnPropertyNames(Teacher.prototype) в поле ввода текста или в вашу консоль JavaScript. Затем введите его снова, заменив Teacher на Person. Новый конструктор не наследует эти методы. Чтобы увидеть это, сравните выводы в консоль Person.prototype.greeting и Teacher.prototype.greeting. Нам нужно заставить Teacher() наследовать методы, определённые на прототипе Person(). Итак, как мы это делаем?

- -
    -
  1. Добавьте следующую строку ниже своего предыдущего добавления: -
    Teacher.prototype = Object.create(Person.prototype);
    - Здесь наш друг create() снова приходит на помощь. В этом случае мы используем его для создания нового объекта и делаем его значением Teacher.prototype. Новый объект имеет свой прототип Person.prototype и, следовательно, наследует, если и когда это необходимо, все доступные методы Person.prototype.
  2. -
  3. Нам нужно сделать ещё одну вещь, прежде чем двигаться дальше. После добавления последней строки, Teacher.prototype.constructor стало равным Person(), потому что мы просто устанавливаем Teacher.prototype для ссылки на объект, который наследует его свойства от Person.prototype! Попробуйте сохранить код, загрузите страницу в браузере и введите Teacher.prototype.constructor в консоль для проверки.
  4. -
  5. Это может стать проблемой, поэтому нам нужно сделать это правильно. Вы можете сделать это, вернувшись к исходному коду и добавив следующие строки внизу: -
    Object.defineProperty(Teacher.prototype, 'constructor', {
    -    value: Teacher,
    -    enumerable: false, // false, чтобы данное свойство не появлялось в цикле for in
    -    writable: true });
    -
  6. -
  7. Теперь, если вы сохраните и обновите, введите Teacher.prototype.constructor, чтобы вернуть Teacher(), плюс мы теперь наследуем Person()!
  8. -
- -

Предоставление Teacher() новой функции greeting()

- -

Чтобы завершить наш код, нам нужно определить новую функцию greeting() в конструкторе Teacher().

- -

Самый простой способ сделать это - определить его на прототипе Teacher() - добавить в нижнюю часть кода следующее:

- -
Teacher.prototype.greeting = function() {
-  var prefix;
-
-  if (this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') {
-    prefix = 'Mr.';
-  } else if (this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') {
-    prefix = 'Mrs.';
-  } else {
-    prefix = 'Mx.';
-  }
-
-  alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.');
-};
- -

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

- -

Попробуйте пример

- -

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

- -
var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');
- -

Теперь сохраните, обновите, и попробуйте получить доступ к свойствам и методам вашего нового объекта teacher1, например:

- -
teacher1.name.first;
-teacher1.interests[0];
-teacher1.bio();
-teacher1.subject;
-teacher1.greeting();
-teacher1.farewell();
- -

Все должно работать нормально. Запросы в строках 1, 2, 3 и 6 унаследованные от общего конструктора Person() (класса). Запрос в строке 4 обращается к subject, доступному только для более специализированного конструктора (класса) Teacher(). Запрос в строке 5 получил бы доступ к методу greeting(), унаследованному от Person(), но Teacher() имеет свой собственный метод greeting() с тем же именем, поэтому запрос обращается к этому методу.

- -
-

Примечание. Если вам не удаётся заставить это работать, сравните свой код с нашей готовой версией (см. также рабочее демо).

-
- -

Методика, которую мы здесь рассмотрели, - это не единственный способ создания наследующих классов в JavaScript, но он работает нормально и это даёт вам представление о том, как реализовать наследование в JavaScript.

- -

Вам также может быть интересно узнать некоторые из новых функций {{glossary("ECMAScript")}}, которые позволяют нам делать наследование более чисто в JavaScript (см. Classes). Мы не рассматривали их здесь, поскольку они пока не поддерживаются очень широко в браузерах. Все остальные конструкторы кода, которые мы обсуждали в этом наборе статей, поддерживаются ещё в IE9 или ранее и есть способы добиться более ранней поддержки, чем это.

- -

Обычный способ - использовать библиотеку JavaScript - большинство популярных опций имеют простой набор функций, доступных для выполнения наследования более легко и быстро. CoffeeScript , например, предоставляет класс, расширяет и т.д.

- -

Дальнейшее упражнение

- -

В нашем руководстве по Объектно-ориентированному JavaScript для начинающих мы также включили класс Student как концепцию, которая наследует все особенности Person, а также имеет другой метод greeting() от Person, который гораздо более неформален, чем приветствие Teacher. Посмотрите, как выглядит приветствие ученика в этом разделе, и попробуйте реализовать собственный конструктор Student(), который наследует все функции Person() и реализует другую функцию greeting().

- -
-

Примечание. Если вам не удаётся заставить это работать, сравните свой код с нашей готовой версией (см. также рабочее демо).

-
- -

Object member summary

- -

Подводя итог, вы в основном получили три типа свойств / методов, о которых нужно беспокоиться:

- -
    -
  1. Те, которые определены внутри функции-конструктора, которые присваиваются экземплярам объекта. Их довольно легко заметить - в вашем собственном коде они представляют собой элементы, определённые внутри конструктора, используя строки this.x = x; в встроенном коде браузера они являются членами, доступными только для экземпляров объектов (обычно создаются путём вызова конструктора с использованием ключевого слова new, например var myInstance = new myConstructor ().
  2. -
  3. Те, которые определяются непосредственно самим конструктором, которые доступны только для конструктора. Они обычно доступны только для встроенных объектов браузера и распознаются путём непосредственной привязки к конструктору, а не к экземпляру. Например, Object.keys().
  4. -
  5. Те, которые определены в прототипе конструктора, которые наследуются всеми экземплярами и наследуют классы объектов. К ним относятся любой член, определённый в свойстве прототипа конструктора, например. myConstructor.prototype.x().
  6. -
- -

Если вы не уверены, что это такое, не беспокойтесь об этом, пока вы ещё учитесь и знание придёт с практикой.

- -

Когда вы используете наследование в JavaScript?

- -

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

- -

В некотором смысле вы используете наследование все время. Всякий раз, когда вы используете различные функции веб-API или методы/свойства, определённые во встроенном объекте браузера, который вы вызываете в своих строках, массивах и т.д., вы неявно используете наследование.

- -

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

- -
-

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

-
- -

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

- -

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

- -

Резюме

- -

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

- -

В следующей статье мы рассмотрим, как работать с JavaScript Object Notation (JSON), общим форматом обмена данными, написанным с использованием объектов JavaScript.

- -

See also

- - - -

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}

- -

В этом модуле

- - diff --git a/files/ru/learn/javascript/objects/object-oriented_js/index.html b/files/ru/learn/javascript/objects/object-oriented_js/index.html deleted file mode 100644 index 409aa367f2..0000000000 --- a/files/ru/learn/javascript/objects/object-oriented_js/index.html +++ /dev/null @@ -1,287 +0,0 @@ ---- -title: Объектно-ориентированный JavaScript для начинающих -slug: Learn/JavaScript/Objects/Object-oriented_JS -tags: - - Constructor - - Create - - JavaScript - - OOJS - - Object - - Новичку - - ООП - - экземпляр -translation_of: Learn/JavaScript/Objects/Object-oriented_JS -original_slug: Learn/JavaScript/Объекты/Object-oriented_JS ---- -
{{LearnSidebar}}
- -
{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}
- -

Разобравшись с основами, сосредоточимся на объектно-ориентированном JavaScript (OOJS) — данная статья даёт базовое представление о теории объектно-ориентированного программирования (ООП), далее рассмотрено как JavaScript эмулирует классы объектов с помощью функции-конструктора и как создаются экземпляры объектов.

- - - - - - - - - - - - -
Необходимые знания: -

Базовая компьютерная грамотность, базовое понимание HTML и CSS, знакомство с основами JavaScript (см. Первые шаги и Cструктурные элементы JavaScript) и основы OOJS (см. Введение в объекты).

-
Цель:Понять основную теорию объектно-ориентированного программирования, как это относится к JavaScript («все является объектом») и как создавать конструкторы и экземпляры объектов.
- -

Объектно-ориентированное программирование: основы

- -

Начнём с упрощённого высокоуровневого представления о том, что такое объектно-ориентированное программирование (ООП). Мы говорим упрощённого, потому что ООП может быстро стать очень сложным, и если сейчас дать полный курс, вероятно, можно запутать больше, чем помочь. Основная идея ООП заключается в том, что мы используем объекты для отображения моделей из реального мира в наших программах и/или упрощения доступа к функциям, которые в противном случае было бы трудно или невозможно использовать.

- -

Объекты могут содержать данные и код, представляющие информацию о том, что вы пытаетесь смоделировать, а также о том, какие у этих объектов должны быть функциональные возможности или поведение. Данные объекта (а часто так же и функции) могут быть точно сохранены (официальный термин "инкапсулированы") внутри пакета объекта, упрощая структуру и доступ к ним. Пакету объекта может быть присвоено определённое имя, на которое можно сослаться и которое иногда называют пространством имён. Объекты также широко используются в качестве хранилищ данных, которые могут быть легко отправлены по сети.

- -

Определение шаблона объекта

- -

Рассмотрим простую программу, которая отображает информацию об учениках и учителях в школе. Здесь мы рассмотрим теорию ООП в целом, а не в контексте какого-либо конкретного языка программирования.

- -

Вернёмся к объекту Person из нашей статьи Основы объектов, который определяет общие сведения и функциональные возможности человека. Есть много вещей, которые вы можете узнать о человеке (его адрес, рост, размер обуви, профиль ДНК, номер паспорта, значимые черты личности ...), но в данном случае нас интересует только имя, возраст, пол и интересы, а также мы хотим иметь возможность написать краткую информацию о нём, основываясь на этих данных, и сделать так, чтобы он поздоровался. Это известно как абстракция — создание простой модели более сложной сущности, которая представляет её наиболее важные аспекты таким образом, чтобы с ней было удобно работать для выполнения целей нашей программы.

- -

- -

В некоторых языках ООП, это общее определение типа объекта называется class (JavaScript использует другой механизм и терминологию, как вы увидите ниже) — это на самом деле не объект, а шаблон, который определяет, какие характеристики должен иметь объект.

- -

Создание реальных объектов

- -

Из нашего класса мы можем создать экземпляры объектов — объекты, содержащие данные и функциональные возможности, определённые в классе. Из нашего класса Person мы теперь можем создавать модели реальных людей:

- -

- -

Когда экземпляр объекта создаётся из класса, для его создания выполняется функция-конструктор класса. Этот процесс создания экземпляра объекта из класса называется создание экземпляра (instantiation) — из класса создаётся экземпляр объекта.

- -

Специализированные классы

- -

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

- -

- -

Это действительно полезно — преподаватели и студенты имеют много общих характеристик, таких как имя, пол и возраст, и удобно определить их только один раз. Вы можете также задать одну и ту же характеристику отдельно в разных классах, поскольку каждое определение этой характеристики будет находиться в отдельном пространстве имён. Например, приветствие студента может быть в форме "Yo, I'm [firstName]" (например Yo, I'm Sam), в то время как учитель может использовать что-то более формальное, такое как "Hello, my name is [Prefix] [lastName], and I teach [Subject]." (например Hello, My name is Mr Griffiths, and I teach Chemistry).

- -
-

Примечание: Если вам интересно, существует специальный термин Polymorphism (Полиморфизм) - это забавное слово, обозначающее реализацию той же функциональности для нескольких типов объекта. 

-
- -

Теперь вы можете создавать экземпляры объекта из дочерних классов. Например:

- -

- -

Далее мы рассмотрим, как ООП теорию можно применить на практике в JavaScript.

- -

Конструкторы и экземпляры объектов

- -

JavaScript использует специальные функции, называемые функциями конструктора (constructor functions) для определения объектов и их свойств. Они полезны, потому что вы часто будете сталкиваться с ситуациями, в которых не известно, сколько объектов вы будете создавать; конструкторы позволяют создать столько объектов, сколько нужно эффективным способом, прикреплением данных и функций для объектов по мере необходимости.

- -

Рассмотрим создание классов через конструкторы и создание экземпляров объектов из них в JavaScript. Прежде всего, мы хотели бы, чтобы вы создали новую локальную копию файла oojs.html, который мы видели в нашей первой статье «Объекты».

- -

Простой пример

- -
    -
  1. Давайте рассмотрим как можно определить человека с нормальной функцией. Добавьте эту функцию в элемент script: - -
    function createNewPerson(name) {
    -  const obj = {};
    -  obj.name = name;
    -  obj.greeting = function() {
    -    alert('Hi! I\'m ' + this.name + '.');
    -  };
    -  return obj;
    -}
    -
  2. -
  3. Теперь вы можете создать нового человека, вызвав эту функцию - попробуйте следующие строки в консоли JavaScript браузера: -
    const salva = createNewPerson('Salva');
    -salva.name;
    -salva.greeting();
    - Это работает достаточно хорошо, но код излишне многословен; если мы знаем, что хотим создать объект, зачем нам явно создавать новый пустой объект и возвращать его? К счастью, JavaScript предоставляет нам удобный способ в виде функций-конструкторов - давайте сделаем это сейчас!
  4. -
  5. Замените предыдущую функцию следующей: -
    function Person(name) {
    -  this.name = name;
    -  this.greeting = function() {
    -    alert('Hi! I\'m ' + this.name + '.');
    -  };
    -}
    -
  6. -
- -

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

- -
-

Примечание: Имя функции конструктора обычно начинается с заглавной буквы - это соглашение используется для упрощения распознавания функций конструктора в коде.

-
- -

Итак, как мы вызываем конструктор для создания некоторых объектов?

- -
    -
  1. Добавьте следующие строки под предыдущим добавлением кода: -
    let person1 = new Person('Bob');
    -let person2 = new Person('Sarah');
    -
  2. -
  3. Сохраните код и перезагрузите его в браузере и попробуйте ввести следующие строки в консоль JS: -
    person1.name
    -person1.greeting()
    -person2.name
    -person2.greeting()
    -
  4. -
- -

Круто! Теперь, как вы видите, у нас есть два новых объекта на странице, каждый из которых хранится в отдельном пространстве имён - при доступе к их свойствам и методам вы должны начинать вызовы с person1 или person2; функциональность, содержащаяся внутри, аккуратно упакована, поэтому она не будет конфликтовать с другими функциями. Тем не менее, у них есть одно и то же свойство name и greeting(). Обратите внимание, что они используют своё собственное значение name, которое было присвоено им, когда они были созданы; это одна из причин, почему очень важно использовать this, таким образом они будут использовать свои собственные значения, а не какие-либо другие.

- -

Давайте снова посмотрим на вызовы конструктора:

- -
let person1 = new Person('Bob');
-let person2 = new Person('Sarah');
- -

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

- -
function Person(name) {
-  this.name = name;
-  this.greeting = function() {
-    alert('Hi! I\'m ' + this.name + '.');
-  };
-}
- -

После создания новых объектов переменные person1 и person2 содержат следующие объекты:

- -
{
-  name: 'Bob',
-  greeting: function() {
-    alert('Hi! I\'m ' + this.name + '.');
-  }
-}
-
-{
-  name: 'Sarah',
-  greeting: function() {
-    alert('Hi! I\'m ' + this.name + '.');
-  }
-}
- -

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

- -

Создавая наш готовый конструктор

- -

Пример, рассмотренный выше, был лишь наглядным примером, чтобы вы поняли суть. Теперь, давайте создадим нашу конечную функцию-конструктор Person().

- -
    -
  1. Замените весь предыдущий код новой функцией конструктора - это, в принципе, тот же самое что и в наглядном примере, но несколько сложнее: -
    function Person(first, last, age, gender, interests) {
    -  this.name = {
    -    first : first,
    -    last: last
    -  };
    -  this.age = age;
    -  this.gender = gender;
    -  this.interests = interests;
    -  this.bio = function() {
    -    alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
    -  };
    -  this.greeting = function() {
    -    alert('Hi! I\'m ' + this.name.first + '.');
    -  };
    -};
    -
  2. -
  3. Теперь добавьте следующую строку ниже, чтобы создать экземпляр объекта из него: -
    let person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
    -
  4. -
- -

Как вы могли заметить, вы можете получить доступ к свойствам и методам, как это было ранее, - попробуйте использовать их в консоли JS:

- -
person1['age']
-person1.interests[1]
-person1.bio()
-// etc.
- -
Примечание: Если у вас возникли проблемы с работой кода, попробуйте сравнить его с нашей версией - см. oojs-class-finished.html (также смотрите, как он работает в прямом эфире).
- -

Дальнейшие упражнения

- -

Для начала, попробуйте добавить ещё пару собственных строк создания объекта и попробуйте получить и установить элементы полученных экземпляров объектов.

- -

Кроме того, есть несколько проблем с нашим методом bio() - вывод всегда включает местоимение «He» ("Он" в пер. с англ.), даже если ваш человек является женщиной или какой-либо другой предпочтительной гендерной классификацией. И bio будет включать только два интереса, даже если в массиве interests указано больше. Можете ли вы решить, как исправить это в определении класса (конструкторе)? Вы можете поместить любой код, который вам нравится внутри конструктора (вам, вероятно, понадобятся несколько условий и цикл). Подумайте о том, как предложения должны быть структурированы по-разному в зависимости от пола и в зависимости от того, имеет ли число перечисленных интересов 1, 2 или более 2.

- -
-

Примечание: Если у вас возникли трудности с решением задачи, мы предоставили ответ в нашем репозитории GitHub (см. это в действии) — но сначала попробуйте написать сами!

-
- -

Другие способы создания экземпляров объектов

- -

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

- -

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

- -

Конструктор Object ()

- -

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

- -
    -
  1. Попробуйте ввести это в консоль JavaScript вашего браузера: -
    let person1 = new Object();
    -
  2. -
  3. Это сохраняет ссылку на пустой объект в переменную person1. Затем вы можете добавить свойства и методы к этому объекту с использованием точечной или скобочной нотации по желанию; попробуйте эти примеры в консоли: -
    person1.name = 'Chris';
    -person1['age'] = 38;
    -person1.greeting = function() {
    -  alert('Hi! I\'m ' + this.name + '.');
    -};
    -
  4. -
  5. Вы также можете передать литерал объекта конструктору Object() в качестве параметра, чтобы заполнить его свойствами / методами. Попробуйте это в консоли JS: -
    let person1 = new Object({
    -  name: 'Chris',
    -  age: 38,
    -  greeting: function() {
    -    alert('Hi! I\'m ' + this.name + '.');
    -  }
    -});
    -
  6. -
- -

Использование метода create()

- -

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

- -

Однако некоторые люди предпочитают создавать экземпляры объектов без предварительного создания конструкторов, особенно если они создают только несколько экземпляров объекта. JavaScript имеет встроенный метод create(), который позволяет вам это делать. С его помощью вы можете создать новый объект на основе любого существующего объекта.

- -
    -
  1. Закончив упражнение из предыдущего раздела, загруженное в браузер, попробуйте это в консоли JavaScript: -
    let person2 = Object.create(person1);
    -
  2. -
  3. Теперь попробуйте: -
    person2.name
    -person2.greeting()
    -
  4. -
- -

Вы увидите, что person2 был создан на основе person1 - он имеет те же свойства и метод, доступные для него.

- -

Одно ограничение метода create() заключается в том, что IE8 не поддерживает его. Поэтому конструкторы могут быть более эффективными, если вы хотите поддерживать старые браузеры.

- -

Подробнее мы рассмотрим особенности метода create() немного позже.

- -

Сводка

- -

В этой статье представлен упрощённый взгляд на объектно-ориентированную теорию — это ещё не вся история, но она даёт представление о том, с чем мы имеем дело. Кроме того, мы начали рассматривать различные способы создания экземпляров объектов.

- -

В следующей статье мы рассмотрим прототипы объектов JavaScript.

- -

{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}

- -

В этом модуле

- - -- cgit v1.2.3-54-g00ecf