From c058fa0fb22dc40ef0225b21a97578cddd0aaffa Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 14:51:05 +0100 Subject: unslug ru: move --- .../learn/javascript/objects/index.html | 356 +++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 files/ru/conflicting/learn/javascript/objects/index.html (limited to 'files/ru/conflicting/learn/javascript/objects/index.html') diff --git a/files/ru/conflicting/learn/javascript/objects/index.html b/files/ru/conflicting/learn/javascript/objects/index.html new file mode 100644 index 0000000000..d07cf043cc --- /dev/null +++ b/files/ru/conflicting/learn/javascript/objects/index.html @@ -0,0 +1,356 @@ +--- +title: Вступление в Объектно-ориентированный JavaScript +slug: Web/JavaScript/Introduction_to_Object-Oriented_JavaScript +translation_of: Learn/JavaScript/Objects +translation_of_original: Web/JavaScript/Introduction_to_Object-Oriented_JavaScript +--- +

Объектно-ориентированный до основания, JavaScript предоставляет мощные и гибкие {{Glossary("OOP")}} возможности. Эта статья начинается с введения в объектно-ориентированное программирование, затем рассматривает модель объекта JavaScript и, наконец, демонстрирует концепции объектно-ориентированного программирования в JavaScript.

+ +

Обзор JavaScript

+ +

Если вы неуверенно владеете такими концепциями JavaScript, как переменные, типы, функции и области видимости, вы можете прочитать об этих темах в Повторное вступление в JavaScript. Вы также можете обратиться к JavaScript Guide.

+ +

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

+ +

Объектно-ориентированное программирование (ООП) — это парадигма программирования, которая использует {{glossary("абстракции")}}, чтобы создавать модели, основанные на объектах реального мира. ООП использует несколько техник из ранее признанных парадигм, включая {{glossary("модульность")}}, {{glossary("полиморфизм")}} и {{glossary("инкапсуляция")}}. На сегодняшний день многие популярные языки программирования (такие как Java, JavaScript, C#, C++, Python, PHP, Ruby и Objective-C) поддерживают ООП.

+ +

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

+ +

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

+ +

Терминология

+ +
+
{{Glossary("Пространство имён")}}
+
Контейнер, который позволяет разработчикам связать весь функционал под уникальным, специфичным для приложения именем.
+
{{Glossary("Класс")}}
+
Определяет характеристики объекта. Класс является описанием шаблона свойств и методов объекта.
+
{{Glossary("Объект")}}
+
Экземпляр класса.
+
{{Glossary("Свойство")}}
+
Характеристика объекта, например, цвет.
+
{{Glossary("Метод")}}
+
Возможности объекта, такие как ходьба. Это подпрограммы или функции, связанные с классом.
+
{{Glossary("Конструктор")}}
+
Метод, вызываемый в момент создания экземпляра объекта. Он, как правило, имеет то же имя, что и класс, содержащий его.
+
{{Glossary("Наследование")}}
+
Класс может наследовать характеристики от другого класса.
+
{{Glossary("Инкапсуляция")}}
+
Способ комплектации данных и методов, которые используют данные.
+
{{Glossary("Абстракция")}}
+
Совокупность комплексных наследований, методов и свойств объекта должны адекватно отражать модель реальности.
+
{{Glossary("Полиморфизм")}}
+
Поли означает "много", а морфизм "формы". Различные классы могут объявить один и тот же метод или свойство.
+
+ +

Для более обширного описания объектно-ориентированного программирования, см {{interwiki("wikipedia", "Объектно-ориентированное_программирование")}} в Wikipedia.

+ +

Прототипное программирование

+ +

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

+ +

Оригинальный (и наиболее каноничный) пример прототипно-ориентированного языка это {{interwiki("wikipedia", "Self (programming language)", "Self")}} разработанный Дэвидом Ангаром и Ренделлом Смитом. Однако бесклассовый стиль программирования стал набирать популярность позднее, и был принят для таких языков программирования, как JavaScript, Cecil, NewtonScript, Io, MOO, REBOL, Kevo, Squeak (при использовании фреймворка Viewer для манипуляции компонентами Morphic) и некоторых других.1

+ +

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

+ +

Пространство имён

+ +

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

+ +
+

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

+
+ +

Принцип работы пространства имён в JS прост: создать один глобальный объект и все переменные, методы и функции объявлять как свойства этого объекта. Также использование пространств имён снижает вероятность возникновения конфликтов имён в приложении так как каждый объект приложения является свойством глобального объекта.

+ +

Давайте создадим глобальный объект MYAPP:

+ +
// Глобальное пространство имён
+var MYAPP = MYAPP || {};
+ +

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

+ +

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

+ +
// Подпространство имён
+MYAPP.event = {};
+ +

Далее следует пример синтаксиса создания пространства имён и добавления переменных, функций и методов:

+ +
// Создаём контейнер MYAPP.commonMethod для общих методов и свойств
+MYAPP.commonMethod = {
+  regExForName: "", // определяет регулярное выражение для валидации имени
+  regExForPhone: "", // определяет регулярное выражение для валидации телефона
+  validateName: function(name){
+    // Сделать что-то с name, вы можете получить доступ к переменной regExForName
+    // используя "this.regExForName"
+  },
+
+  validatePhoneNo: function(phoneNo){
+    // Сделать что-то с номером телефона
+  }
+}
+
+// Объект вместе с объявлением методов
+MYAPP.event = {
+    addListener: function(el, type, fn) {
+    // код
+    },
+    removeListener: function(el, type, fn) {
+    // код
+    },
+    getEvent: function(e) {
+    // код
+    }
+
+    // Можно добавить другие свойства и методы
+}
+
+// Синтаксис использования метода addListener:
+MYAPP.event.addListener("yourel", "type", callback);
+ +

Стандартные встроенные объекты

+ +

В JavaScript есть несколько объектов, встроенных в ядро, например {{jsxref("Math")}}, {{jsxref("Object")}}, {{jsxref("Array")}} и {{jsxref("String")}}. Пример ниже показывает как использовать объект Math, чтобы получить случайное число, используя его метод random().

+ +
console.log(Math.random());
+
+ +
Примечание: В данном примере и далее мы будем использовать глобальную функцию {{domxref("console.log()")}}. Если точнее, то функция console.log() не является частью JavaScript, но она поддерживается многими браузерами для облегчения отладки.
+ +

Смотрите JavaScript Reference: Standard built-in objects, чтобы ознакомиться со списком всех встроенных объектов JavaScript.

+ +

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

+ +

Объекты, создаваемые пользователем

+ +

Класс

+ +

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

+ +
var Person = function () {};
+
+ +

Объект (экземпляр класса)

+ +

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

+ +

В примере выше мы определили класс Person. В примере ниже мы создаём два его экземпляра (person1 и person2).

+ +
var person1 = new Person();
+var person2 = new Person();
+
+ +
Ознакомьтесь с {{jsxref("Object.create()")}}, новым, дополнительным методом инстанцирования, который создаёт неинициализированный экземпляр.
+ +

Конструктор

+ +

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

+ +

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

+ +

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

+ +
var Person = function () {
+  console.log('instance created');
+};
+
+var person1 = new Person();
+var person2 = new Person();
+
+ +

Свойство (аттрибут объекта)

+ +

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

+ +

Ключевое слово this, которое ссылается на текущий объект, позволяет вам работать со свойствами класса. Доступ (чтение и запись) к свойствам снаружи класса осуществляется синтаксисом InstanceName.Property, так же как в C++, Java и некоторых других языках. (Внутри класса для получения и изменения значений свойств используется синтаксис this.Property)

+ +

В примере ниже, мы определяем свойство firstName для класса Person при создании экземпляра:

+ +
var Person = function (firstName) {
+  this.firstName = firstName;
+  console.log('Person instantiated');
+};
+
+var person1 = new Person('Alice');
+var person2 = new Person('Bob');
+
+// Выводит свойство firstName в консоль
+console.log('person1 is ' + person1.firstName); // выведет "person1 is Alice"
+console.log('person2 is ' + person2.firstName); // выведет "person2 is Bob"
+
+ +

Методы

+ +

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

+ +

В примере ниже мы определяем и используем метод sayHello() для класса Person.

+ +
var Person = function (firstName) {
+  this.firstName = firstName;
+};
+
+Person.prototype.sayHello = function() {
+  console.log("Hello, I'm " + this.firstName);
+};
+
+var person1 = new Person("Alice");
+var person2 = new Person("Bob");
+
+// вызываем метод sayHello() класса Person
+person1.sayHello(); // выведет "Hello, I'm Alice"
+person2.sayHello(); // выведет "Hello, I'm Bob"
+
+ +

В JavaScript методы это — обычные объекты функций, связанные с объектом как свойства: это означает, что вы можете вызывать методы "вне контекста". Рассмотрим следующий пример:

+ +
var Person = function (firstName) {
+  this.firstName = firstName;
+};
+
+Person.prototype.sayHello = function() {
+  console.log("Hello, I'm " + this.firstName);
+};
+
+var person1 = new Person("Alice");
+var person2 = new Person("Bob");
+var helloFunction = person1.sayHello;
+
+// выведет "Hello, I'm Alice"
+person1.sayHello();
+
+// выведет "Hello, I'm Bob"
+person2.sayHello();
+
+// выведет "Hello, I'm undefined" (or fails
+// with a TypeError in strict mode)
+helloFunction();
+
+// выведет true
+console.log(helloFunction === person1.sayHello);
+
+// выведет true
+console.log(helloFunction === Person.prototype.sayHello);
+
+// выведет "Hello, I'm Alice"
+helloFunction.call(person1);
+ +

Как показывает пример, все ссылки, которые мы имеем на функцию sayHello — person1, Person.prototype, переменная helloFunction и т.д. — ссылаются на одну и ту же функцию. Значение this в момент вызова функции зависит от того, как мы её вызываем. Наиболее часто мы обращаемся к this в выражениях, где мы получаем функцию из свойства объекта — person1.sayHello() — this устанавливается на объект, из которого мы получили функцию (person1), вот почему person1.sayHello() использует имя "Alice", а person2.sayHello() использует имя "Bob". Но если вызов будет совершён иначе, то this будет иным: вызов this из переменной — helloFunction() — установит this на глобальный объект (window в браузерах). Так как этот объект (вероятно) не имеет свойства firstName, функция выведет "Hello, I'm undefined" (так произойдёт в нестрогом режиме; в strict mode всё будет иначе (ошибка), не будем сейчас вдаваться в подробности, чтобы избежать путаницы). Или мы можем указать this явно с помощью Function#call (или Function#apply) как показано в конце примера.

+ +
Примечание: Смотрите подробнее о this в  Function#call и Function#apply
+ +

Наследование

+ +

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

+ +
Примечание: JavaScript не обнаружит prototype.constructor класса потомка (смотрите Object.prototype) так что мы должны указать его вручную. Смотрите вопрос "Why is it necessary to set the prototype constructor?" на Stackoverflow.
+ +

В примере ниже мы определяем класс Student как потомка класса Person. Потом мы переопределяем метод sayHello() и добавляем метод addGoodBye().

+ +
// Определяем конструктор Person
+var Person = function(firstName) {
+  this.firstName = firstName;
+};
+
+// Добавляем пару методов в Person.prototype
+Person.prototype.walk = function(){
+  console.log("I am walking!");
+};
+
+Person.prototype.sayHello = function(){
+  console.log("Hello, I'm " + this.firstName);
+};
+
+// Определяем конструктор Student
+function Student(firstName, subject) {
+  // Вызываем конструктор родителя, убедившись (используя Function#call)
+  // что "this" в момент вызова установлен корректно
+  Person.call(this, firstName);
+
+  // Инициируем свойства класса Student
+  this.subject = subject;
+};
+
+// Создаём объект Student.prototype, который наследуется от Person.prototype.
+// Примечание: Рспространённая ошибка здесь, это использование "new Person()", чтобы создать
+// Student.prototype. Это неверно по нескольким причинам, не в последнюю очередь
+// потому, что нам нечего передать в Person в качестве аргумента "firstName"
+// Правильное место для вызова Person показано выше, где мы вызываем
+// его в конструкторе Student.
+Student.prototype = Object.create(Person.prototype); // Смотрите примечание выше
+
+// Устанавливаем свойство "constructor" для ссылки на класс Student
+Student.prototype.constructor = Student;
+
+// Заменяем метод "sayHello"
+Student.prototype.sayHello = function(){
+  console.log("Hello, I'm " + this.firstName + ". I'm studying "
+              + this.subject + ".");
+};
+
+// Добавляем метод "sayGoodBye"
+Student.prototype.sayGoodBye = function(){
+  console.log("Goodbye!");
+};
+
+// Пример использования:
+var student1 = new Student("Janet", "Applied Physics");
+student1.sayHello();   // "Hello, I'm Janet. I'm studying Applied Physics."
+student1.walk();       // "I am walking!"
+student1.sayGoodBye(); // "Goodbye!"
+
+// Проверяем, что instanceof работает корректно
+console.log(student1 instanceof Person);  // true
+console.log(student1 instanceof Student); // true
+
+ +

Относительно строки Student.prototype = Object.create(Person.prototype);: В старых движках JavaScript, в которых нет  Object.create можно использовать полифилл (ещё известный как "shim") или функцию которая достигает тех же результатов, такую как:

+ +
function createObject(proto) {
+    function ctor() { }
+    ctor.prototype = proto;
+    return new ctor();
+}
+
+// Пример использования:
+Student.prototype = createObject(Person.prototype);
+
+ +
Примечание: Смотрите Object.create для более подробной информации, и shim для реализации на старых движках.
+ +

Инкапсуляция

+ +

В примере выше классу Student нет необходимости знать о реализации метода walk() класса Person, но он может его использовать; Класс Student не должен явно определять этот метод, пока мы не хотим его изменить. Это называется инкапсуляция, благодаря чему каждый класс собирает данные и методы в одном блоке.

+ +

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

+ +

Абстракция

+ +

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

+ +

В JavaScript класс Function наследуется от класса Object (это демонстрирует специализацию), а свойство Function.prototype это экземпляр класса Object (это демонстрирует композицию).

+ +
var foo = function () {};
+
+// выведет "foo is a Function: true"
+console.log('foo is a Function: ' + (foo instanceof Function));
+
+// выведет "foo.prototype is an Object: true"
+console.log('foo.prototype is an Object: ' + (foo.prototype instanceof Object));
+ +

Полиморфизм

+ +

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

+ +

Примечания

+ +

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

+ +

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

+ +

Ссылки

+ +
    +
  1. Wikipedia. "Object-oriented programming"
  2. +
  3. Wikipedia. "Encapsulation (object-oriented programming)"
  4. +
-- cgit v1.2.3-54-g00ecf