update classes
This commit is contained in:
44
docs/javascript/05-prototypes/01-prototype-inheritance.md
Normal file
44
docs/javascript/05-prototypes/01-prototype-inheritance.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Прототипное наследование
|
||||||
|
|
||||||
|
- В JavaScript все объекты имеют скрытое свойство `[[Prototype]]`, которое является либо другим объектом, либо `null`.
|
||||||
|
- Мы можем использовать `obj.__proto__` для доступа к нему (исторически обусловленный геттер/сеттер, есть другие способы, которые скоро будут рассмотрены).
|
||||||
|
- Объект, на который ссылается `[[Prototype]]`, называется «прототипом».
|
||||||
|
- Если мы хотим прочитать свойство `obj` или вызвать метод, которого не существует у `obj`, тогда JavaScript попытается найти его в прототипе.
|
||||||
|
- Операции записи/удаления работают непосредственно с объектом, они не используют прототип (если это обычное свойство, а не сеттер).
|
||||||
|
- Если мы вызываем `obj.method()`, а метод при этом взят из прототипа, то `this` всё равно ссылается на `obj`. Таким образом, методы всегда работают с текущим объектом, даже если они наследуются.
|
||||||
|
- Цикл `for..in` перебирает как свои, так и унаследованные свойства. Остальные методы получения ключей/значений работают только с собственными свойствами объекта.
|
||||||
|
|
||||||
|
## Prototype
|
||||||
|
В JavaScript объекты имеют специальное скрытое свойство `[[Prototype]]` (так оно названо в спецификации), которое либо равно `null`, либо ссылается на другой объект.\
|
||||||
|
Когда мы хотим прочитать свойство из object, а оно отсутствует, JavaScript автоматически берёт его из прототипа. В программировании такой механизм называется «прототипным наследованием».
|
||||||
|
|
||||||
|
Свойство `[[Prototype]]` является внутренним и скрытым, но есть много способов задать его.
|
||||||
|
|
||||||
|
Одним из них является использование `__proto__`
|
||||||
|
|
||||||
|
💥 Свойство `__proto__` — исторически обусловленный геттер/сеттер для `[[Prototype]]`\
|
||||||
|
Обратите внимание, что __proto__ — не то же самое, что внутреннее свойство [[Prototype]].
|
||||||
|
|
||||||
|
Это геттер/сеттер для `[[Prototype]]`. Позже мы увидим ситуации, когда это имеет значение, а пока давайте просто будем иметь это в виду, поскольку мы строим наше понимание языка JavaScript.
|
||||||
|
|
||||||
|
Свойство `__proto__` немного устарело, оно существует по историческим причинам. Современный JavaScript предполагает, что мы должны использовать функции `Object.getPrototypeOf/Object.setPrototypeOf` вместо того, чтобы получать/устанавливать прототип. Мы также рассмотрим эти функции позже.
|
||||||
|
|
||||||
|
По спецификации `__proto__` должен поддерживаться только браузерами, но по факту все среды, включая серверную, поддерживают его. Так что мы вполне безопасно его используем.
|
||||||
|
|
||||||
|
## Операция записи не использует прототип
|
||||||
|
Прототип используется только для чтения свойств. \
|
||||||
|
Операции записи/удаления работают напрямую с объектом.
|
||||||
|
|
||||||
|
## Значение «this»
|
||||||
|
***Неважно, где находится метод: в объекте или его прототипе. При вызове метода `this` — всегда объект перед точкой.***
|
||||||
|
|
||||||
|
Таким образом, вызов сеттера `admin.fullName=` в качестве `this` использует `admin`, а не `user`.
|
||||||
|
|
||||||
|
## Цикл for…in
|
||||||
|
Цикл `for..in` проходит не только по собственным, но и по унаследованным свойствам объекта.
|
||||||
|
|
||||||
|
Если унаследованные свойства нам не нужны, то мы можем отфильтровать их при помощи встроенного метода `obj.hasOwnProperty(key)`: он возвращает `true`, если у `obj` есть собственное, не унаследованное, свойство с именем `key`.
|
||||||
28
docs/javascript/05-prototypes/02-f-prototype.md
Normal file
28
docs/javascript/05-prototypes/02-f-prototype.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
# F.prototype
|
||||||
|
|
||||||
|
Как мы помним, новые объекты могут быть созданы с помощью функции-конструктора new F().
|
||||||
|
|
||||||
|
Если в F.prototype содержится объект, оператор new устанавливает его в качестве [[Prototype]] для нового объекта.
|
||||||
|
|
||||||
|
💥 На заметку:
|
||||||
|
JavaScript использовал прототипное наследование с момента своего появления. Это одна из основных особенностей языка.
|
||||||
|
|
||||||
|
Но раньше, в старые времена, прямого доступа к прототипу объекта не было. Надёжно работало только свойство "prototype" функции-конструктора, описанное в этой главе. Поэтому оно используется во многих скриптах.
|
||||||
|
|
||||||
|
- Свойство `F.prototype` (не путать с `[[Prototype]]`) устанавливает `[[Prototype]]` для новых объектов при вызове `new F()`.
|
||||||
|
- Значение `F.prototype` должно быть либо объектом, либо `null`. Другие значения не будут работать.
|
||||||
|
- Свойство `"prototype"` является особым, только когда оно назначено функции-конструктору, которая вызывается оператором `new`.
|
||||||
|
-
|
||||||
|
В обычных объектах prototype не является чем-то особенным:
|
||||||
|
```js
|
||||||
|
let user = {
|
||||||
|
name: "John",
|
||||||
|
prototype: "Bla-bla" // никакой магии нет - обычное свойство
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
По умолчанию все функции имеют `F.prototype = { constructor: F }`, поэтому мы можем получить конструктор объекта через свойство `"constructor"`.
|
||||||
66
docs/javascript/05-prototypes/03-build-in-prototypes.md
Normal file
66
docs/javascript/05-prototypes/03-build-in-prototypes.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# Встроенные прототипы
|
||||||
|
|
||||||
|
- Все встроенные объекты следуют одному шаблону:
|
||||||
|
- Методы хранятся в прототипах (Array.prototype, Object.prototype, Date.prototype и т.д.).
|
||||||
|
- Сами объекты хранят только данные (элементы массивов, свойства объектов, даты).
|
||||||
|
- Примитивы также хранят свои методы в прототипах объектов-обёрток: Number.prototype, String.prototype, Boolean.prototype. Только у значений undefined и null нет объектов-обёрток.
|
||||||
|
- Встроенные прототипы могут быть изменены или дополнены новыми методами. Но не рекомендуется менять их. Единственная допустимая причина – это добавление нового метода из стандарта, который ещё не поддерживается движком JavaScript.
|
||||||
|
|
||||||
|
|
||||||
|
## Object.prototype
|
||||||
|
Краткая нотация `obj = {}` – это то же самое, что и `obj = new Object()`, где `Object` – встроенная функция-конструктор для объектов с собственным свойством `prototype`, которое ссылается на огромный объект с методом `toString` и другими.
|
||||||
|
```js
|
||||||
|
let obj = {};
|
||||||
|
alert( obj ); // "[object Object]" ?
|
||||||
|
```
|
||||||
|
Таким образом, когда вызывается obj.toString(), метод берётся из Object.prototype.
|
||||||
|
|
||||||
|
## Другие встроенные прототипы
|
||||||
|
Другие встроенные объекты, такие как Array, Date, Function и другие, также хранят свои методы в прототипах.
|
||||||
|
|
||||||
|
## Примитивы
|
||||||
|
Самое сложное происходит со строками, числами и булевыми значениями.
|
||||||
|
|
||||||
|
Если мы попытаемся получить доступ к их свойствам, то тогда будет создан временный объект-обёртка с использованием встроенных конструкторов String, Number и Boolean, который предоставит методы и после этого исчезнет.
|
||||||
|
Эти объекты создаются невидимо для нас, и большая часть движков оптимизирует этот процесс, но спецификация описывает это именно таким образом. Методы этих объектов также находятся в прототипах, доступных как String.prototype, Number.prototype и Boolean.prototype.
|
||||||
|
|
||||||
|
💥 **Значения null и undefined не имеют объектов-обёрток**
|
||||||
|
|
||||||
|
## Изменение встроенных прототипов
|
||||||
|
Встроенные прототипы можно изменять. Например, если добавить метод к String.prototype, метод становится доступен для всех строк:
|
||||||
|
```js
|
||||||
|
String.prototype.show = function() {
|
||||||
|
alert(this);
|
||||||
|
};
|
||||||
|
"BOOM!".show(); // BOOM!
|
||||||
|
```
|
||||||
|
💥 Важно:
|
||||||
|
Прототипы глобальны, поэтому очень легко могут возникнуть конфликты. Если две библиотеки добавляют метод String.prototype.show, то одна из них перепишет метод другой.
|
||||||
|
|
||||||
|
Изменение встроенных прототипов считается плохой идеей.
|
||||||
|
*** В современном программировании есть только один случай, в котором одобряется изменение встроенных прототипов. Это создание полифилов.***
|
||||||
|
|
||||||
|
## Заимствование у прототипов
|
||||||
|
Некоторые методы встроенных прототипов часто одалживают.
|
||||||
|
|
||||||
|
Например, если мы создаём объект, похожий на массив (псевдомассив), мы можем скопировать некоторые методы из Array в этот объект.
|
||||||
|
```js
|
||||||
|
let obj = {
|
||||||
|
0: "Hello",
|
||||||
|
1: "world!",
|
||||||
|
length: 2,
|
||||||
|
};
|
||||||
|
obj.join = Array.prototype.join;
|
||||||
|
alert( obj.join(',') ); // Hello,world!
|
||||||
|
```
|
||||||
|
Это работает, потому что для внутреннего алгоритма встроенного метода `join` важны только корректность индексов и свойство `length`, он не проверяет, является ли объект на самом деле массивом. И многие встроенные методы работают так же.
|
||||||
|
|
||||||
|
Альтернативная возможность – мы можем унаследовать от массива, установив `obj.__proto__` как `Array.prototype`, таким образом все методы `Array` станут автоматически доступны в `obj`.
|
||||||
|
|
||||||
|
Но это будет невозможно, если `obj` уже наследует от другого объекта. Помните, мы можем наследовать только от одного объекта одновременно.
|
||||||
|
|
||||||
|
Заимствование методов – гибкий способ, позволяющий смешивать функциональность разных объектов по необходимости.
|
||||||
31
docs/javascript/05-prototypes/04-prototype-methods.md
Normal file
31
docs/javascript/05-prototypes/04-prototype-methods.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
# Методы прототипов, объекты без свойства __proto__
|
||||||
|
Свойство `__proto__` считается устаревшим, и по стандарту оно должно поддерживаться только браузерами.
|
||||||
|
|
||||||
|
Современные же методы это:
|
||||||
|
|
||||||
|
- `Object.create(proto[, descriptors])` – создаёт пустой объект со свойством [[Prototype]], указанным как proto, и необязательными дескрипторами свойств `descriptors`.
|
||||||
|
- `Object.getPrototypeOf(obj)` – возвращает свойство `[[Prototype]]` объекта `obj`.
|
||||||
|
- `Object.setPrototypeOf(obj, proto)` – устанавливает свойство `[[Prototype]]` объекта `obj` как `proto`.
|
||||||
|
|
||||||
|
Эти методы нужно использовать вместо `__proto__`.
|
||||||
|
|
||||||
|
Встроенный геттер/сеттер `__proto__` не безопасен, если мы хотим использовать созданные пользователями ключи в объекте. Как минимум потому, что пользователь может ввести "__proto__" как ключ, от чего может возникнуть ошибка. Если повезёт – последствия будут лёгкими, но, вообще говоря, они непредсказуемы.
|
||||||
|
|
||||||
|
Так что мы можем использовать либо `Object.create(null)` для создания «простейшего» объекта, либо использовать коллекцию `Map`.
|
||||||
|
|
||||||
|
Кроме этого, `Object.create` даёт нам лёгкий способ создать поверхностную копию объекта со всеми дескрипторами:
|
||||||
|
|
||||||
|
`__proto__` – это геттер/сеттер для свойства `[[Prototype]]`, и находится он в `Object.prototype`, как и другие методы.
|
||||||
|
|
||||||
|
Ещё методы:
|
||||||
|
- `Object.keys(obj)` / `Object.values(obj)` / `Object.entries(obj)` – возвращают массив всех перечисляемых собственных строковых ключей/значений/пар ключ-значение.
|
||||||
|
- `Object.getOwnPropertySymbols(obj)` – возвращает массив всех собственных символьных ключей.
|
||||||
|
- `Object.getOwnPropertyNames(obj)` – возвращает массив всех собственных строковых ключей.
|
||||||
|
- `Reflect.ownKeys(obj)` – возвращает массив всех собственных ключей.
|
||||||
|
- `obj.hasOwnProperty(key)`: возвращает `true`, если у `obj` есть собственное (не унаследованное) свойство с именем `key`.
|
||||||
|
|
||||||
|
Все методы, которые возвращают свойства объектов (такие как `Object.keys` и другие), возвращают «собственные» свойства. Если мы хотим получить и унаследованные, можно воспользоваться циклом `for..in`.
|
||||||
51
docs/javascript/06-classes/01-class-base.md
Normal file
51
docs/javascript/06-classes/01-class-base.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Класс: базовый синтаксис
|
||||||
|
MyClass технически является функцией (той, которую мы определяем как constructor), в то время как методы, геттеры и сеттеры записываются в MyClass.prototype.
|
||||||
|
|
||||||
|
## Синтаксис «class»
|
||||||
|
```js
|
||||||
|
class MyClass {
|
||||||
|
// методы класса
|
||||||
|
constructor() { ... }
|
||||||
|
method1() { ... }
|
||||||
|
method2() { ... }
|
||||||
|
method3() { ... }
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Затем используйте вызов `new MyClass()` для создания нового объекта со всеми перечисленными методами.
|
||||||
|
|
||||||
|
При этом автоматически вызывается метод `constructor()`, в нём мы можем инициализировать объект.
|
||||||
|
|
||||||
|
💥 **Методы в классе не разделяются запятой**
|
||||||
|
|
||||||
|
## Что такое класс?
|
||||||
|
В JavaScript класс – это разновидность функции.
|
||||||
|
|
||||||
|
Вот что на самом деле делает конструкция `class User {...}`:
|
||||||
|
|
||||||
|
1. Создаёт функцию с именем `User`, которая становится результатом объявления класса. Код функции берётся из метода `constructor` (она будет пустой, если такого метода нет).
|
||||||
|
2. Сохраняет все методы, такие как `sayHi`, в `User.prototype`.
|
||||||
|
|
||||||
|
При вызове метода объекта `new User` он будет взят из прототипа, как описано в главе `F.prototype`. Таким образом, объекты new User имеют доступ к методам класса.
|
||||||
|
|
||||||
|
## Геттеры/сеттеры, другие сокращения
|
||||||
|
Как и в литеральных объектах, в классах можно объявлять вычисляемые свойства, геттеры/сеттеры и т.д.
|
||||||
|
При объявлении класса геттеры/сеттеры создаются на `User.prototype`
|
||||||
|
|
||||||
|
## Свойства классов
|
||||||
|
В приведённом выше примере у класса `User` были только методы.
|
||||||
|
```js
|
||||||
|
class User {
|
||||||
|
name = "Аноним";
|
||||||
|
|
||||||
|
sayHi() {
|
||||||
|
alert(`Привет, ${this.name}!`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new User().sayHi();
|
||||||
|
```
|
||||||
|
Свойство name не устанавливается в `User.prototype`. Вместо этого оно создаётся оператором `new` перед запуском конструктора, это именно свойство объекта.
|
||||||
48
docs/javascript/06-classes/02-inheritance-classes.md
Normal file
48
docs/javascript/06-classes/02-inheritance-classes.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
# Наследование классов
|
||||||
|
Наследование классов – это способ расширения одного класса другим классом.
|
||||||
|
Таким образом, мы можем добавить новый функционал к уже существующему.
|
||||||
|
|
||||||
|
1. Чтобы унаследовать от класса: class Child extends Parent:
|
||||||
|
-При этом Child.prototype.__proto__ будет равен Parent.prototype, так что методы будут унаследованы.
|
||||||
|
2. При переопределении конструктора:
|
||||||
|
- Обязателен вызов конструктора родителя super() в конструкторе Child до обращения к this.
|
||||||
|
3. При переопределении другого метода:
|
||||||
|
- Мы можем вызвать super.method() в методе Child для обращения к методу родителя Parent.
|
||||||
|
4. Внутренние детали:
|
||||||
|
- Методы запоминают свой объект во внутреннем свойстве [[HomeObject]]. Благодаря этому работает super, он в его прототипе ищет родительские методы.
|
||||||
|
- Поэтому копировать метод, использующий super, между разными объектами небезопасно.
|
||||||
|
|
||||||
|
- У стрелочных функций нет своего this и super, поэтому они «прозрачно» встраиваются во внешний контекст.
|
||||||
|
|
||||||
|
## Ключевое слово «extends»
|
||||||
|
Синтаксис создания класса допускает указывать после extends не только класс, но и любое выражение.
|
||||||
|
Пример вызова функции, которая генерирует родительский класс:
|
||||||
|
```js
|
||||||
|
function f(phrase) {
|
||||||
|
return class {
|
||||||
|
sayHi() { alert(phrase); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
class User extends f("Привет") {}
|
||||||
|
new User().sayHi(); // Привет
|
||||||
|
```
|
||||||
|
Здесь class User наследует от результата вызова f("Привет").
|
||||||
|
|
||||||
|
## Переопределение методов
|
||||||
|
```js
|
||||||
|
class Rabbit extends Animal {
|
||||||
|
stop() {
|
||||||
|
// ...теперь это будет использоваться для rabbit.stop()
|
||||||
|
// вместо stop() из класса Animal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
У классов есть ключевое слово "super", чтобы сделать новый на его основе, изменяя или расширяя его функциональность
|
||||||
|
|
||||||
|
super.method(...) вызывает родительский метод.
|
||||||
|
super(...) для вызова родительского конструктора (работает только внутри нашего конструктора).
|
||||||
46
docs/javascript/06-classes/03-static-option-methods.md
Normal file
46
docs/javascript/06-classes/03-static-option-methods.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# Статические свойства и методы
|
||||||
|
Статические методы используются для функциональности, принадлежат классу «в целом», а не относятся к конкретному объекту класса.
|
||||||
|
|
||||||
|
Например, метод для сравнения двух статей Article.compare(article1, article2) или фабричный метод Article.createTodays().
|
||||||
|
|
||||||
|
В объявлении класса они помечаются ключевым словом static.
|
||||||
|
|
||||||
|
Статические свойства используются в тех случаях, когда мы хотели бы сохранить данные на уровне класса, а не какого-то одного объекта.
|
||||||
|
|
||||||
|
```js
|
||||||
|
class MyClass {
|
||||||
|
static property = ...;
|
||||||
|
|
||||||
|
static method() {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Технически, статическое объявление – это то же самое, что и присвоение классу:
|
||||||
|
```
|
||||||
|
MyClass.property = ...
|
||||||
|
MyClass.method = ...
|
||||||
|
```
|
||||||
|
Статические свойства и методы наследуются.
|
||||||
|
|
||||||
|
Для class B extends A прототип класса B указывает на A: B.[[Prototype]] = A. Таким образом, если поле не найдено в B, поиск продолжается в A.
|
||||||
|
|
||||||
|
## Статические свойства
|
||||||
|
Статические свойства также возможны, они выглядят как свойства класса, но с static в начале:
|
||||||
|
```js
|
||||||
|
class Article {
|
||||||
|
static publisher = "Илья Кантор";
|
||||||
|
}
|
||||||
|
alert( Article.publisher ); // Илья Кантор
|
||||||
|
```
|
||||||
|
Это то же самое, что и прямое присваивание Article:
|
||||||
|
```
|
||||||
|
Article.publisher = "Илья Кантор";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Наследование статических свойств и методов
|
||||||
|
Статические свойства и методы наследуются.
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
# Приватные и защищённые методы и свойства
|
||||||
|
В терминах ООП отделение внутреннего интерфейса от внешнего называется инкапсуляция.
|
||||||
|
|
||||||
|
Это даёт следующие выгоды:
|
||||||
|
|
||||||
|
**Защита для пользователей, чтобы они не выстрелили себе в ногу**
|
||||||
|
|
||||||
|
Если мы чётко отделим внутренний интерфейс, то разработчик класса сможет свободно менять его внутренние свойства и методы, даже не информируя пользователей…
|
||||||
|
#### Поддерживаемость
|
||||||
|
Если вы разработчик такого класса, то приятно знать, что приватные методы можно безопасно переименовывать, их параметры можно изменять и даже удалять, потому что от них не зависит никакой внешний код.
|
||||||
|
|
||||||
|
В новой версии вы можете полностью всё переписать, но пользователю будет легко обновиться, если внешний интерфейс остался такой же.
|
||||||
|
|
||||||
|
## Внутренний и внешний интерфейсы
|
||||||
|
В объектно-ориентированном программировании свойства и методы разделены на 2 группы:
|
||||||
|
|
||||||
|
- Внутренний интерфейс – методы и свойства, доступные из других методов класса, но не снаружи класса.
|
||||||
|
- Внешний интерфейс – методы и свойства, доступные снаружи класса.
|
||||||
|
|
||||||
|
Итак, всё, что нам нужно для использования объекта, это знать его внешний интерфейс. Мы можем совершенно не знать, как это работает внутри, и это здорово.
|
||||||
|
|
||||||
|
В JavaScript есть два типа полей (свойств и методов) объекта:
|
||||||
|
- Публичные: доступны отовсюду. Они составляют внешний интерфейс. До этого момента мы использовали только публичные свойства и методы.
|
||||||
|
- Приватные: доступны только внутри класса. Они для внутреннего интерфейса.
|
||||||
|
|
||||||
|
Защищённые поля не реализованы в JavaScript на уровне языка, но на практике они очень удобны, поэтому их эмулируют.
|
||||||
|
|
||||||
|
## Защищённое свойство «waterAmount»
|
||||||
|
Защищённые свойства обычно начинаются с префикса `_`.
|
||||||
|
|
||||||
|
Это не синтаксис языка: есть хорошо известное соглашение между программистами, что такие свойства и методы не должны быть доступны извне. Большинство программистов следуют этому соглашению.
|
||||||
|
|
||||||
|
## Приватное свойство «#waterLimit»
|
||||||
|
Есть новшество в языке JavaScript, которое почти добавлено в стандарт: оно добавляет поддержку приватных свойств и методов.
|
||||||
|
|
||||||
|
Приватные свойства и методы должны начинаться с #. Они доступны только внутри класса.
|
||||||
|
|
||||||
|
Например, в классе ниже есть приватное свойство #waterLimit и приватный метод #checkWater для проверки количества воды
|
||||||
|
|
||||||
|
На уровне языка # является специальным символом, который означает, что поле приватное. Мы не можем получить к нему доступ извне или из наследуемых классов.
|
||||||
|
|
||||||
|
Приватные поля не конфликтуют с публичными. У нас может быть два поля одновременно – приватное #waterAmount и публичное waterAmount.
|
||||||
46
docs/javascript/06-classes/05-class-check.md
Normal file
46
docs/javascript/06-classes/05-class-check.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 5
|
||||||
|
---
|
||||||
|
|
||||||
|
# Проверка класса: "instanceof"
|
||||||
|
|
||||||
|
| | работает для | возвращает |
|
||||||
|
|-------------|----------------------------------------------------------------|------------|
|
||||||
|
| typeof | примитивов | строка |
|
||||||
|
| {}.toString | примитивов, встроенных объектов, объектов с Symbol.toStringTag | строка |
|
||||||
|
| instanceof | объектов | true/false |
|
||||||
|
|
||||||
|
Как мы можем видеть, технически `{}.toString` «более продвинут», чем `typeof`.
|
||||||
|
|
||||||
|
А оператор `instanceof` – отличный выбор, когда мы работаем с иерархией классов и хотим делать проверки с учётом наследования.
|
||||||
|
|
||||||
|
## Оператор instanceof
|
||||||
|
```js
|
||||||
|
obj instanceof Class
|
||||||
|
```
|
||||||
|
Оператор вернёт `true`, если `obj` принадлежит классу Class или наследующему от него.
|
||||||
|
|
||||||
|
## Object.prototype.toString возвращает тип
|
||||||
|
У `toString` имеются скрытые возможности, которые делают метод гораздо более мощным. Мы можем использовать его как расширенную версию `typeof` и как альтернативу `instanceof`.
|
||||||
|
|
||||||
|
Согласно спецификации встроенный метод `toString` может быть позаимствован у объекта и вызван в контексте любого другого значения. И результат зависит от типа этого значения.
|
||||||
|
|
||||||
|
- Для числа это будет [object Number]
|
||||||
|
- Для булева типа это будет [object Boolean]
|
||||||
|
- Для null: [object Null]
|
||||||
|
- Для undefined: [object Undefined]
|
||||||
|
- Для массивов: [object Array]
|
||||||
|
- …и т.д. (поведение настраивается).
|
||||||
|
|
||||||
|
## Symbol.toStringTag
|
||||||
|
Поведение метода объектов `toString` можно настраивать, используя специальное свойство объекта `Symbol.toStringTag`.
|
||||||
|
```js
|
||||||
|
// toStringTag для браузерного объекта и класса
|
||||||
|
alert( window[Symbol.toStringTag]); // window
|
||||||
|
alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest
|
||||||
|
alert( {}.toString.call(window) ); // [object Window]
|
||||||
|
alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]
|
||||||
|
```
|
||||||
|
В итоге мы получили «typeof на стероидах», который не только работает с примитивными типами данных, но также и со встроенными объектами, и даже может быть настроен.
|
||||||
|
|
||||||
|
Можно использовать `{}.toString.call` вместо `instanceof` для встроенных объектов, когда мы хотим получить тип в виде строки, а не просто сделать проверку.
|
||||||
15
docs/javascript/06-classes/06-mixins.md
Normal file
15
docs/javascript/06-classes/06-mixins.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 6
|
||||||
|
---
|
||||||
|
|
||||||
|
# Примеси
|
||||||
|
По определению из Википедии, примесь – это класс, методы которого предназначены для использования в других классах, причём без наследования от примеси.
|
||||||
|
|
||||||
|
Примесь – общий термин в объектно-ориентированном программировании: класс, который содержит в себе методы для других классов.
|
||||||
|
|
||||||
|
С примесями могут возникнуть конфликты, если они перезаписывают существующие методы класса. Стоит помнить об этом и быть внимательнее при выборе имён для методов примеси, чтобы их избежать.
|
||||||
|
|
||||||
|
## Пример примеси
|
||||||
|
Простейший способ реализовать примесь в JavaScript – это создать объект с полезными методами, которые затем могут быть легко добавлены в прототип любого класса.\
|
||||||
|
Это не наследование, а просто копирование методов.
|
||||||
|
Примеси могут наследовать друг друга.
|
||||||
Reference in New Issue
Block a user