JavaScript Crash Course
ООП в JavaScript
8
$ whoami
Інна Іващук
Senior Software Engineer
JS developer, music fan, movie-dependent and Star Wars fan 🤓
May the Force be with you!
Зміст:
-
Принципи ООП
-
Класи vs функції конструктори
-
Прототипи
-
this, execution context та області видимості
-
.bind(), .call(), .apply()
Принципи ООП
Що таке ООП?
Об'єктно-орієнтоване програмування (in english OOP) – це модель програмування яка базується на стверджені того, що програма це сукупність об’єктів які взаємодіють між собою. Кожен об’єкт в цій моделі є незалежним, і він здатний отримувати, обробляти дані та відправляти ці дані іншим об’єктам.
В ООП використано моделі наслідування, поліморфізму та інкапсуляції.
Наслідування (Inheritance)
Наслідування - принцип об'єктно-орієнтованого програмування, що дозволяє створювати ієрархічні структури об'єктів. Використовуючи наслідування можна створити загальний клас, який буде визначати характеристики, поведінку і властиві певному набору пов'язаних об'єктів.
Наслідування (Inheritance)
function Car(model) {
this.model = model;
this.getModel = () => this.model;
this.drive = () => console.log('Driving....');
}
const BMW = new Car('BMW');
const Volvo = new Car('Volvo');
BMW.drive(); // Driving...
Volvo.drive(); // Driving...
Клас або функція-конструктор
Нащадки або наслідники
BMW
Volvo
Поліморфізм (Polymorphism)
Поліморфізм (від греч. πολὺ - багато, і μορφή - форма) в мовах програмування - можливість об'єктів з однаковою специфікацією мати різну реалізацію.
Animal
Dog
Cat
.speak() // woof!
.speak() // meow!
class Animal {
constructor(name) {
this.name = name;
}
sound() { return ''; }
toString() {
return Object.getPrototypeOf(this).constructor.name;
}
}
class Cat extends Animal {
constructor(name) {
super(name);
}
sound() {
return 'Meow!';
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
sound() {
return 'Woof!';
}
}
const Tom = new Cat('Tom');
Tom.sound(); // Meow!
const Rex = new Dog('Rex');
Rex.sound(); // Woof!
Приклад з використанням класів
Інкапсуляція (Encapsulation)
Інкапсуляція – механізм, який поєднує дані та методи, що обробляють ці дані і захищає і те і інше від зовнішнього впливу або невірного використання.
E
n
c
a
p
s
u
l
a
t
i
o
n
Variables
Methods
Class
const createCounter = () => {
// A variable defined in a factory or constructor function scope
// is private to that function.
let count = 0;
return ({
// Any other functions defined in the same scope are privileged:
// These both have access to the private `count` variable
// defined anywhere in their scope chain (containing function
// scopes).
click: () => count += 1,
getCount: () => count.toLocaleString()
});
};
const counter = createCounter();
counter.click();
counter.click();
counter.click();
console.log(
counter.getCount()
);
Real Encapsulation in JavaScript
Приклад використання
Класи vs функції конструктори
function Cat(name, color) {
this.name = name;
this.color = color;
this.run = function () {
console.log("I’m running");
};
this.sound = function () {
console.log("Meow! Meow!");
};
}
const Tom = new Cat("Tom", "grey");
const Simon = new Cat("Simon", "red");
Функція конструктор
class Cat {
constructor(name, color) {
this.name = name;
this.color = color;
}
run() {
console.log(this.name + " is running");
}
sound() {
console.log("Meow! Meow!");
}
}
const Felix = new Cat("Felix", "white");
Використання класів
class Cat {
constructor(name, color) {
this.name = name;
this.color = color;
}
run() {
console.log(this.name + " is running");
}
sound() {
console.log("Meow! Meow!");
}
}
class LazyCat extends Cat {
constructor(name, color) {
super(name, color)
}
run() {
console.log(this.name + ' is too lazy to run');
}
}
const Simon = new LazyCat("Simon", "grey");
const Felix = new Cat("Felix", "white");
Використання класів
Прототипи
Прототипи (Prototype)
Властивість прототип - спочатку порожній об'єкт. До якого можуть бути додані функції і властивості, як і для будь-якого іншого об'єкта.
Кожен об'єкт в JavaScript має "секретну" властивість, яке додається при визначенні або ініціалізації об'єкта. Дана властивість має ім'я __proto__. Саме через нього здійснюється доступ до ланцюжку прототипу.
function
object1
object2
prototype
instance of
links to
__proto__
__proto__
function Cat(name, color) {
this.name = name;
this.color = color;
}
Cat.prototype.run = function () {
console.log("I’m running");
};
Cat.prototype.sound = function () {
console.log("Meow! Meow!");
};
const Tom = new Cat("Tom", "grey");
const Simon = new Cat("Simon", "red");
Функція конструктор + методи додані в prototype
this, execution context та області видимості
Область видимості
Область видимості - важлива концепція, що визначає доступність змінних. Ця концепція є основою замикань, поділяючи змінні на глобальні і локальні. this - це доступ до області
Область видимості
Механізм роботи функцій і змінних в JavaScript відрізняється від інших мов програмування. Існують наступні області видимості:
-
Глобальна - змінні і функції не перебувають всередині якоїсь функції. Тобто, іншими словами, якщо змінна або функція не перебувають всередині конструкції function, то вони - «глобальні»;
-
Локальна - змінні і функції доступні тільки всередині конструкції function;
-
Блочна - змінні і функції доступні тільки у визначеному блоці (ES6).
Ключове слово this
Значення this – це об'єкт, який використовувався для виклику методу. В залежності від області видимості, ключове слово this буде посилатись на відповідний контекст функції, наприклад на глобальний об'єкт (Window в браузері), в іншому випадку - контекст функції.
const user = {
name: "Michael",
age: 30,
sayHi() {
// this - is "current object"
console.log(this.name);
}
};
user.sayHi(); // Michael
Об'єкт на який посилається this можна змінювати, використовуючи call() або bind() aбо apply()
this в стрілочній функції
Стілочна функція немає свого контексту і завжди використовує контекст, де вона задекларована і викликається.
const arrowFn1 = () => {
console.log(this);
}
function Circle() {
this.PI = 3.14;
this.r = 20;
this.getArea = () => {
console.log(this);
return this.PI * Math.pow(this.r, 2);
}
}
const cr = new Circle();
cr.getArea();
Область видимості
Область видимості: функції і змінні
const a = 10;
console.log(c); // is not available
function plusC() {
const c = 100;
return a + c; // a is available
}
Область видимості: цикли і їх змінні
let res = 0;
console.log(i); // i - is not available
for (let i = 0; i < 10; i++) {
res += i;
}
console.log(i); // i - also is not available
Область видимості: методи і їх змінні
const array = [1, 2, 3, 4];
let res = 0;
console.log(item); // is not available
array.forEach(item => {
res += item;
})
console.log(item); // also is not available
Контекст виконання (Execution context)
const x = 10;
function foo() {
const y = 20;
function bar() {
const z = 15;
const output = x + y + z;
return output;
}
return bar;
}
foo()();
Global Execution Context
Execution Context (foo)
Execution Context (bar)
.bind(), .call(), .apply()
Зміна контексту виконання з bind()
const module = {
x: 42,
getX: function() {
return this.x;
}
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
Зміна контексту виконання з допомогою bind()
const module = {
x: 42,
getX: function() {
return this.x;
}
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
Зміна контексту виконання з допомогою call()
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
Зміна контексту виконання з допомогою apply()
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.apply(this, [name, price]);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
Можна використовувати як і метод .call() тільки з тією відмінністю, що аргументи потрібно передавати у вигляді масиву
Використання apply() в комбінації з Math
const numbers = [5, 6, 2, 3, 7];
// Find the largest number in array
const max = Math.max.apply(null, numbers);
console.log(max);
// Expected output: 7
// Find the smallest number in array
const min = Math.min.apply(null, numbers);
console.log(min);
// Expected output: 2
// Whithout .apply()
const maxPassingNumbers = Math.max(5,6,3,2,1);
// or
const maxUsingSpread = Math.max(...numbers);
Q & A
_10 JavaScript Crash Course
By Inna Ivashchuk
_10 JavaScript Crash Course
- 589