Визначення класів
Класи в JavaScript були введені в ECMAScript 2015. Це собою синтаксичний цукор над механізмом прототипного успадкування. Синтаксис класів не вводить нову об’єктно-орієнтовану модель, а простіший спосіб створення об’єктів і організації успадкування.
Можна визначати класи за допомогою: class declarations і class expressions.
Перший спосіб визначення класу - class declaration (оголошення класу). Для цього необхідно скористатися ключовим словом class і вказати ім’я класу.
class Rectangle {
constructor (height, width) {
this.height = height;
this.width = width;
}
}Різниця між оголошенням функції (function declaration) і оголошенням класу (class declaration) в тому, що оголошення функції здійснює підйом (hoisting), в той час як оголошення класу - ні. Тому спочатку необхідно оголосити клас і тільки потім працювати з ним.
Другий спосіб визначення класу - class expression. Можна створювати іменовані і безіменні вираження. У першому випадку ім’я вираження класу знаходиться в локальній області видимості класу і може бути отримано через властивості самого класу, а не його екземпляра.
// безіменний
var Rectangle = class {
constructor (height, width) {
this.height = height;
this.width = width;
}
};// іменований
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
let inst = new MyClass();
console.log(inst.getClassName());Тіла класів виконуються в строгому режимі (strict mode).
Метод constructor і ключове слово super
constructor() необхідний для ініціалізації об’єктів, створених, за допомогою класу. Може бути тільки один у класі, інакше отримаємо виняток типу SyntaxError.
constructor() визначає функцію, яка представляє собою клас: Foo === Foo.prototype.constructor > true typeof Foo > 'function'
Ключове слово super використовується в методі constructor для виклику конструктора батьківського класу. Також використовується для виклику функцій батьківського класу.
Статичні і прототипні методи класу
Ключове слово static, визначає статичний метод для класу. Статичні методи не можуть бути викликані в екземплярах (instance) класу.
Прототипні методи наслідуються екземплярами класу.
JavaScript Object Property Descriptors
Метод Object.defineProperty дозволяє оголосити властивість і налаштувати її дескриптор.
Метод приймає три параметри Object.defineProperty(obj, “property”, {descriptor}).
obj – об’єкт, в якому оголошується чи змінюється властивість;
“property” – назва властивості;
{descriptor} – об’єкт, який описує поведінку властивості при виконанні певних операцій над нею, як зчитування або запис.
Є дескриптор даних і дескриптор доступу (data descriptor і access descriptor).
Дескриптор даних дає можливість налаштовувати такі атрибути властивості як:
value – значення властивості (за замовчуванням default);
writable – визначає, чи можна змінювати значення напряму через object.property;
configurable – визначає, чи можна видаляти або модифікувати за допомогою Object.defineProperty();
enumerable – визначає чи буде властивість перелічуваною. Кожен об’єкт можна перебрати за допомогою циклу for .. in або ж отримати назви всіх властивостей за допомогою функції Object.keys. enumerable визначає, чи буде властивість перелічуватися в даних ситуаціях.
const fox = {};
Object.defineProperties(fox, {
'name': {
value: 'Oliver',
enumerable: false
},
'type': {
value: 'fox',
enumerable: true
}
});for (let key in fox) {
console.log(${key}: ${fox[key]}); // type: fox
}
Object.keys(fox).forEach(key => {
console.log(${key}: ${fox[key]}); // type: fox
});
(writable, configurable, enumerable за замовчуванням false)
const human = {};
Object.defineProperty(
human,
“age”,
{
value: 10,
writable: false,
configurable: true,
enumerable: false
}
)console. log(human.age); // 10
human. age = 90;
console. log(human.age); // 10
Дескриптор доступу описується парою функцій – гетером і сетером. Такий дескриптор може містити get(), set(), configurable, enumerable.
Недоліом методу defineProperty() є його повторні виклики для кожного визначення властивості.
Для визначення декількох властивостей за один виклик використовуєтсья метод defineProperties().
const jar = {};
Object.defineProperties(jar, {
"numberOfCookies": {
value: 0,
configurable: true
},
"cookies": {
get(){
return this.numberOfCookies;
},
set(value){
if (value >= 0 && value <= 5) {
Object.defineProperty(this, "numberOfCookies",
{ value: value });
} else {
console.error('Количество печенек должно быть от
0 до 5');
}
},
enumerable: true
}
});console. log(jar.cookies); // 0
jar. numberOfCookies = 4;
console. log(jar.cookies); // 0
jar. cookies = 4;
console. log(jar.cookies); // 4
JavaScript Object Accessors
Object Accessors це функції getter і setter. Їх синтаксис нагадує методи об’єктів, але на початку вказуємо ключові слова get чи set.
set пов’язує властивість об’єкта з функцією, яка буде викликана при спробі встановити нове значення цієї властивість.
get пов’язує властивість об’єкта з функцією, яка буде викликатися при зверненні до цієї властивості.
getter повертає значення властивості, а setter приймає нове значення і встановлює його властивості.
const jar = {
numberOfCookies: 0,
get cookies() {
return this.numberOfCookies;
},
set cookies(value) {
this.numberOfCookies = value;
}
};Щоб отримати значення numberOfCookies => jar.cookies. Виглядає ніби звертаємося до властивості cookies, але насправді ми викликаємо функцію get за іменем cookies.
Jar.cookies = 5 – викликаємо функцію set за іменем cookies.
Така конструкція дає можливість проводити валідацію значення, яке встановлюється.
set cookies(value) {
If ( value >=0 ) {
this.numberOfCookies = value;
} else {
console.error(“Error”)
}
}Але проблема в тому, що нічого не заважає встановити значення властивості напряму через jar.numberOfCookies = 599.
Для вирішення цієї проблеми використовують метод Object.defineProperty.
OOP Principles
Абстракция - когда переводим объект реального мира в программный объект, то выделяем только те характеристики, которые нужны для выполнения конкретной задачи.
Абстрагирование – это способ выделить набор значимых характеристик объекта, исключая из рассмотрения незначимые. Соответственно, абстракция – это набор всех таких характеристик.
Инкапсуляция - класс может иметь приватные свойства и методы, реализация которых скрыта от внешнего мира, и к которым объекты не имеют прямого доступа, а могут вызывать только публичные методы класса. Таким образом класс как бы скрывает часть своего функционала от пользователя.
Инкапсуляция – это свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе и скрыть детали
реализации от пользователя.
Наследование - дочерний класс унаследует от родительского класс все методы и свойства.
Наследование – это свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью. Класс, от которого производится наследование, называется базовым или родительским. Новый класс – потомком, наследником или производным классом.
Полиморфизм - возможность разной реализации методов одного интерфейса.
Например есть несколько классов, которые унаследуют от одного класса, и они имеют разные реализации определенного метода родительского класса.
Полиморфизм – это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.
Наследование, композиция, агрегация - виды отношения объектов
Наследование — это когда класс-наследник имеет все поля и методы родительского класса, и, как правило, добавляет какой-то новый функционал или/и поля.
Ассоциация – это когда один класс включает в себя другой класс в качестве одного из полей. Ассоциация описывается словом «имеет». Автомобиль имеет двигатель. Вполне естественно, что он не будет являться наследником двигателя.
Выделяют два частных случая ассоциации: композицию и агрегацию.
Композиция - включаемый класс может существовать только как часть контейнера (другого класса). Если контейнер будет уничтожен, то и включённый класс тоже будет уничтожен. Экземпляр включенного класса будет создаваться в конструкторе контейнера.
Агрегация – это когда экземпляр включенного класса передается в конструктор контейнера в качестве параметра и может существовать отдельно от контейнера.
Объект
Объект - модель реальной сущности, имеющая конкретные свойства и методы. Объект - екземпляр класса.
ООП и JS
JavaScript — это объектно-ориентированный язык, основанный на прототипировании, а не на классах.
Основанные на классах объектно-ориентированные языки строятся на концепции двух отдельных сущностей: класс и экземпляр.
Класс определяет все свойства, которые характеризуют группу объектов. Класс это абстрактная вещь, а не какой-либо конкретный член множества объектов.
Экземпляр, это воплощение класса в виде конкретного объекта.
JavaScript имеет только объекты. Но имеет понятие прототипа объекта — это объект, используемый в качестве шаблона, с целью задать изначальные свойства для нового объекта.
Любой объект может иметь собственные свойства, присвоенные либо во время создания, либо во время выполнения. Любой объект может быть указан в качестве прототипа для другого объекта.
В классо-ориентированных языках, вы можете определить класс и метод конструктор, чтобы задать начальные значения для свойств экземпляра. Для создания экземпляра класса используется оператор new, совместно с методом конструктора.
В JavaScript определяется функция-конструктор для создания объектов с начальным набором свойств и значений. Любая функция в JavaScript может быть использована, как конструктор. Используется оператор new для создания нового объекта.
В языках, основанных на классах, иерархию классов создается через объявление классов. В объявлении класса вы можете указать, что новый класс является подклассом уже существующего класса.
JavaScript реализует наследование присвоением экземпляра объекта в качестве значения свойства prototype функции-конструктора.
Присваиваем новый экземпляр Employee, в качестве prototype для функции-конструктора Manager. Теперь, когда вы создадите нового Manager, он унаследует свойства из объекта Employee.
function Employee() {
this.name = '';
this.dept = 'general';
}function WorkerBee() {
this.projects = [];
}WorkerBee.prototype = new Employee(); var mark = new WorkerBee();
Когда JavaScript видит оператор new, он создает новый объект и неявно устанавливает значение внутреннего свойства [[Prototype]] в WorkerkBee.prototype, затем передает этот новый объект в качестве значения this в функцию-конструктор WorkerBee. Внутреннее свойство [[Prototype]] определяет цепочку прототипов, используемых для получения значений свойств.
Когда вы запрашиваете значение свойства, JavaScript сначала проверяет, существует ли это значение в данном объекте. Если так и есть, тогда возвращается это значение. Если значение не найдено в самом объекте, JavaScript проверяет цепочку прототипов (используя внутреннее свойство [[Prorotype]]).
Поиск свойств в JavaScript начинается с просмотра самого объекта, и если в нем свойство не найдено, поиск переключается на объект, на который указывает ссылка __proto__.
Специальное свойство __proto__ устанавливается автоматически при создании объекта. Оно принимает значение свойства prototype функции-конструктора.
mark.__proto__ == WorkerBee.prototype //true
Все объекты (за исключением глобального объекта Object) имеют свойство __proto__. Все функции имеют свойство prototype.
Оператор instanceof - способ проверки, наследуется ли объект от конкретного конструктора.
Метод Object.create()
Метод Object.create() создаёт новый объект с указанными объектом прототипа и свойствами.
Float
Определяет, по какой стороне будет выравниваться элемент, при этом остальные элементы будут обтекать его с других сторон. Когда значение свойства float равно none, элемент выводится на странице как обычно, при этом допускается, что одна строка обтекающего текста может быть на той же линии, что и сам элемент.
Eсть ли разница между window и document?
Да. У JavaScript есть глобальный объект и всё происходит через него. window – тот самый объект, который хранит глобальные переменные, функции, местоположение, историю. Всё находится внутри него, setTimeout, XMLHttpRequest, console и localStorage также являются частью window. Аналогично дело обстоит и с document, который является свойством объекта window и представляет DOM. Все ноды – это часть document, следовательно, вы можете использовать getElementById или addEventListener для document. Но обратите внимание, что этих методов нет в объекте window.
RxJS
Библиотека для работы с асинхронными данными в виде потока, например клики мыши, или скрол. В центре находится объект Observable и набор операторов для работы с ним.