2. Задача 0.
• Создать массив объектов – товаров. У каждого товара есть название, цена,
масса. Создать не менее 6 товаров.
• Создать объект Склад. У склада есть метод извлечения товара – он
принимает название, цену товара и возвращает объект товара с
указанными названием и ценой и случайной массой.
• Создать два объекта Магазин. В магазине есть название, также в нем
хранится массив товаров, есть метод для добавления товара и очистки
магазина. В магазине есть метод, возвращающий общую стоимость всех
товаров в магазине.
• Создать 6 товаров с использованием Склада. Распределить созданные
товары по двум магазинам. Вызвать методы подсчета стоимости товаров в
магазинах и вывести их результат в консоль.
3. Защита объектов
• Защита объектов – специальный приём, позволяющий для
некоторого объект предотвратить использование на нём
модифицирующих операций.
4. Уровни защиты объектов
const item = { /* Object content */}
Object.preventExtensions(item);
// Запрет расширения.
// В объект больше нельзя добавить новые свойства.
Object.seal(item);
// Запечатывание. Включает запрет расширения.
// Из объекта нельзя удалить существующие свойства
Object.freeze(item);
// Заморозка. Включает запечатывание.
// В объекте нельзя изменить значение существующих свойств
5. Добавление свойств при помощи
дескрипторов
• Создавать новые свойства в объекте можно путем простого
присваивания новому полю значения:
• Тем не менее, в Javascript объекты и их свойства обладают более
гибким функционалом. Создавать свойства можно при помощи
дескрипторов – этот подход позволит настроить уровни доступа к
полю такого объекта.
const item = { /* Object content */};
item.x = 10;
6. DefineProperty
• При создании свойства
через defineProperty в
объекте дескрипторов
указываются поля,
отвечающие за различные
уровни доступа к этому
полю.
const item = { /* Object content */};
Object.defineProperty(item, 'x', {
// Descriptors
})
Object.defineProperty(item, 'x', {
value: 10,
writable: true,
configurable: false,
enumerable: true,
})
7. Дескрипторы
Дескриптор Значение Описание
value any Значение в поле
enumerable true|false Если задано false, то поле не будет участвовать в
обходе объекта циклом for..in
configurable true|false Если задано false, то поле нельзя удалить
оператором delete и изменить дескрипторы
writable true|false Если задано false, то полю нельзя задать другое
значение
set function Если задана функция, то она будет вызываться в
случаях, когда в поле присваивается новое значение
get function Если задана функция, то она будет вызываться в
случаях, когда значение поля вызывается для чтения.
Несовместимо с дескриптором value.
9. Задача 1.
• Создать объект человека. У него в полях есть имя и год рождения.
• Создать свойство «возраст». При чтении оно вернет возраст
человека в годах. При записи оно поменяет год рождения человека
так, чтобы тот соответствовал переданному возрасту.
10. Прокси-объекты
• Прокси-объектом называется объект специального рода, который
замещает собой некоторый оригинальный объект и осуществляет
предварительную обработку всех операций, направляемых на
объект.
Proxy ОбъектСкрипт
11. Создание Proxy
• Прокси-объект как бы
подменяет собой
оригинальный. Далее вся
работа в скрипте
осуществляется только через
этот прокси-объект.
• В объекте с handlers
описываются методы-ловушки,
реагирующие на действия с
объектом-прокси.
const originalPoint = {
x: 10,
y: 20,
}
const point = new Proxy(originalPoint, {
// Action handlers
});
console.log(point.x); // 10
12. Ловушки (handlers) Proxy
const point = new Proxy(originalPoint, {
get(target, prop, receiver) {
if (prop in target) {
return target[prop];
}
return 'Prop not found!';
}
});
console.log(point.x); // 10
console.log(point.z); // "Prop not found!"
const point = new Proxy(originalPoint, {
set(target, prop, value, receiver) {
if(typeof value !== 'number') {
return false;
}
if(value < 0) {
value = 0;
}
target[prop] = value;
return true;
}
});
point.x = 10; // 10
point.x = -10; // 0
point.x = '10'; // 0
13. Типы ловушек
Тип Описание
get Вызывается, когда из прокси читается какое-либо свойство
set Вызывается, когда в прокси задается какое-либо свойство
has Вызывается, когда на прокси применяется оператор in
deleteProperty Вызывается, когда на прокси вызывается оператор delete
apply Вызывается, когда на прокси вызывается оператор () – вызов как функцию
construct Вызов на прокси оператора new.
… Дополнительные ловушки, связанные с объектной обработкой прокси
В одном прокси-объекте может быть по одной ловушке каждого типа.
Если ловушка отсутствует, то соответствующая операция
пробрасывается мимо прокси на проксируемый объект.
14. Задача 2.
• Создать прокси на объект человека. Не позволять создавать новые
поля, а при записи года человеку проверять, чтобы он был не в
будущем и не более чем на 120 лет в прошлом. Если эти условия не
соблюдаются, оставлять текущий год рождения.
16. Базовые принципы ООП
• Классом называется инструкция, по которой происходит создание новых
объектов того или иного типа.
• В ООП класс – базовая структурная единица. Объекты, создаваемые в ОО-
приложении, всегда относятся к какому-то классу.
• Тот факт, что объект относится к какому-то классу, позволяет четко
понимать, какие поля и методы он в себе содержит и как можно с ними
работать.
• В ОО-приложении весь код строится на взаимодействии некоторых
строго определенных в классах сущностей. Это позволяет искусственно
сжать круг возможностей в коде до четко определенного набора
операций и ошибиться становится сложнее.
17. Создание класса в Javascript
• Для создания классов используются три паттерна:
• Фабрика (генератор объектов)
• Конструктор
• Прототип
• Кроме того, в ES6 появился синтаксический сахар для работы с
ООП. Но он, по сути, является комбинацией паттерна Конструктор +
прототип.
18. Паттерн Фабрика
function Human(name, age) {
return {
name: name,
age: age,
getBirthYear() {
return (new Date).getFullYear() - this.age;
}
};
}
const man = Human('Alex', 30);
console.log(man); //{name: 'Alex', age: 30, getBirthYear: f}
19. Паттерн Конструктор
function Human(name, age) {
this.name = name;
this.age = age;
this.getBirthYear = function () {
return (new Date).getFullYear() - this.age;
}
}
const man = new Human('Alex', 30);
console.log(man); //{name: 'Alex', age: 30, getBirthYear: f}
20. Паттерн Прототип
function Human(name, age) {
this.name = name;
this.age = age;
}
Human.prototype.getBirthYear = function() {
return (new Date).getFullYear() - this.age;
}
const man = new Human('Alex', 30);
console.log(man); //{name: 'Alex', age: 30}
console.log(man.getBirthYear()); // 2000
21. Сравнение паттернов
• Паттерн Фабрика – самый простой паттерн. Но он не позволяет
реализовать наследование, не позволяет узнать, к какому классу
относится созданный объект.
• Паттерн Конструктор позволяет реализовать наследование и узнать
порождающий класс. Однако в нём создаются дубликаты методов.
• Паттерн Прототип расширяет конструктор, позволяя вынести
общие для всех экземпляров класса методы и свойства в одну точку
без дублирования.
22. Порождающий конструктор
• У объекта, созданного при помощи конструктора, существует
свойство constructor, которое ссылается на функцию-конструктор, с
помощью которой был создан объект.
• Оператор instanceof принимает в себя объект и функцию и
возвращает true, если объект был создан при помощи этой
функции-конструктора.
const man = new Human('Alex', 30);
console.log(man.constructor); // Human
console.log(man instanceof Human); // true
23. Задача 3.
• Создать класс Студент. У студента есть имя, курс, массив оценок за
курс. У студента есть метод получения его среднего балла.
• Создать класс Факультет. У факультета есть название и массив
обучающихся студентов. Создать метод зачисления студента на
факультет. Создать метод, который вернет средний балл всех
студентов на факультете.
• Создать 4 объекта класса Студент и один факультет. Зачислить
студентов на факультет, вывести средний балл всех студентов в
факультете.
24. Собственные свойства
• Собственными для объекта называются свойства, созданные
напрямую в конструкторе либо добавленные в этот объект вручную.
• Несобственными будут свойства, доступные в этом объекте, но
находящиеся в прототипе.
function X() {
this.a = 10;
this.b = 20;
}
X.prototype.c = 30;
X.prototype.d = 40;
const x = new X();
console.log(x.a, x.b, x.c, x.d);
25. Установка наличия свойства
• Оператор in вернет true
если свойство в
принципе доступно в
объекте – не важно,
собственное или нет.
• Метод hasOwnProperty у
любого объекта вернет
true только если
переданное в него
свойство является
собственным.
function X() {
this.a = 10;
this.b = 20;
}
X.prototype.c = 30;
X.prototype.d = 40;
const x = new X();
console.log(x.a, x.b, x.c, x.d);
console.log('a' in x); // true
console.log('d' in x); // true
console.log(x.hasOwnProperty('b')) // true
console.log(x.hasOwnProperty('c')) // false
26. Переопределение прототипа
• Свойство constructor, присутствующее у
объектов, является несобственным
(прототипным).
• Если в коде Вы перезаписываете прототип
полностью (а не дописываете), то
необходимо дополнить прототип
свойством constructor вручную (см.
пример)
function X() {
this.a = 10;
}
X.prototype = {
constructor: X,
getA() {},
getB() {},
getC() {}
}
27. Расширение базового прототипа
• Иногда можно встретить подход, расширяющий возможности
встроенных объектов, например:
• Этот подход наделяет базовые объекты новыми возможностями.
• Однако использовать такой подход сегодня не принято – он
существенно ухудшает читаемость кода и ослабляет устойчивость
кода.
const arr = [10, 20, 30];
Array.prototype.sum = function() {
return this.reduce((s, v) => s + v, 0);
}
console.log(arr.sum()); // 60
28. Прототипное наследование
function Car(model) {
this.model = model;
}
Car.prototype.drive = function () {
console.log('Dr-dr-dr-dr-dr');
}
function AmbulanceCar(model, capacity) {
Car.apply(this, [model]);
// or Car.call(this, model);
this.capacity = capacity;
}
AmbulanceCar.prototype = Object.create(Car.prototype);
AmbulanceCar.prototype.alert = function () {
console.log('Whe-o-whe-o-whe-o');
}
const car = new Car('Volvo');
car.drive();
const ambulance =
new AmbulanceCar('Volvo', 4);
ambulance.drive();
ambulance.alert();
29. Статические методы
• Статическими методами называются методы, которые относятся ко
всему классу целиком, а не только к экземпляру.
function Car(model) {
this.model = model;
Car.amount ++;
}
Car.amount = 0;
Car.printAmount = function() {
console.log(this.amount);
}
const cars = [new Car('BMV'), new Car('Volvo'), new Car('Porshe')];
Car.printAmount();
30. Классы в ES6
class Car {
model = '';
static amount = 0;
constructor(model) {
this.model = model;
Car.amount++;
}
drive() {
console.log('Dr-r-r-r-r-r')
}
static printAmount() {
console.log(this.amount);
}
}
32. Дополнительные материалы
Object.seal
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Gl
obal_Objects/Object/seal
Создание свойств с дескрипторами
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Gl
obal_Objects/Object/defineProperty
Proxy - простые примеры
https://habr.com/ru/company/ruvds/blog/359060/
Proxy - описание на MDN
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Gl
obal_Objects/Proxy
Proxy - описание на learn.javascript.ru
https://learn.javascript.ru/proxy
Прототипы
https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%
D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object_proto
types
Введение в ООП
https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%
D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object-
oriented_JS
Прототипное наследование
https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%
D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Inheritance
ООП в ES6
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Cl
asses