JavaScript OOP Flashcards
Обяснете какво е обектно-ориентирано програмиране.
ООП е набор от принципи, които трябва да следваме, ако искаме да използваме обекти като основен начин за организиране на нашия код./Класове, прайвет фиилдс.
Някои от тези принципи се поддържат от езикови характеристики
Други са по-абстрактни принципи, които трябва да следваме, когато пишем код. Кода трябва да предоставя възможност за бързо фасилитиране на промените според изискванията на клиентите
-Обяснете какво представляват класовете и за какво можем да ги използваме.
Класовете са основната езикова функция, която ни позволява да използваме ООП Те са обектни шаблони, които се използват за моделиране:
Състояние (използвайки променливи, които наричаме полета /възможност за дефолтни стойности/)
Поведение (използвайки функции, които наричаме методи) Инстанции са обектит създадени на база на класа/шаблона/
// Example class class Person { // Model the person }
// Objects created using the class const person1 = new Person(); const person2 = new Person();
State classPerson{ name='Pesho'; age=20; } Behavior classPerson{ name; speak(){ return`HelloI\'m${this.name}`; } }
Моделирайте клас за изразяване на конкретно състояние и поведение.
Полетата са част от данните на класа
Те са еквивалент на променливи и състоянието на обекта. Полетата могат да имат стойност по подразбиране
Методите са част от класа, и позволяват изпълнение на действие Свързаните полета и методи трябва да бъдат поставени в един и същи клас
Методите могат да взаимодействат с полетата
class Person {
name;
sayName() {
console.log(Hello I am ${this.name}
);
}
}
Създайте обект (инстанция) с помощта на клас.
const gosho = new Person();
gosho. name = ‘Gosho’;
gosho. sayName();
Създайте обект (инстанция) с помощта на конструктор.
class Person { name;
constructor(initialName){ this.name = initialName; } sayName() { console.log(`Hello I am ${this.name}!`); } } // create instances whit constructor const gosho = new Person('Gosho'); gosho.sayName(); //implicid binding
Добавете документация в кода с помощта на JSDoc. https://jsdoc.app/
/** */ записваме коментари, които се визуализират в останалите файлове и в браузера, като документация. Инсталираме глобално пакета npm install -g jsdocГенерираме документация в папка docs посредством команда - jsdoc person.js -d dosc https://www.npmjs.com/package/jsdoc /** This class represents a Peron */ install -g jsdoc jsdoc person.js -d dosc. https://jsdoc.app/tags-param.html Documenting a destructuring parameter как конкретно да описваме типа на параметрите в документацията
-Обяснете разликата между OOP и FP.
OOP е парадигма на програмиране и се отнася до стил на програмиране, не се отнася до конкретен език, а по-скоро до начина, по който се структурира кода Процедурно програмиране – Записване на стъпките, които вашата програма трябва да изпълни по ред Функционално програмиране - Организиране на вашия код в множество функции, където всяка функция работи сама по себе си
Обектно-ориентирано програмиране - Организиране на вашия код в класове и обекти (обектите са базирани на класове)”
// Procedural programming Записване на стъпките, които вашата програма трябва да изпълни по ред const button = document.querySelector('button'); const doSomething = () => { // doSomething... }; button.addEventListener('click', doSomething); Functional programming -Организиране на вашия код в множество функции,където всяка функция работи сама по себе си
function findElementOnPage(elementTag) { return document.querySelector(elementTag); } function doSomething() { //do Something } function attachEvent(selector, eventType, action) { const btn = findElementOnPage(selector); btn.addEventListener(eventType, action); }
attachEvent(‘button’, ‘click’, doSomething);
Object-oriented programming Организиране на вашия код в класове и обекти (обектите са базирани на класове)
class InputArea { button;
constructor(){ this.button = document.querySelector('button'); this.button.addEventListener('click', this.doSomething); } doSomething(){ //do Something } }
const area = new InputArea();
Какво е ООП? - Какво представляват класовете и защо те са една от основните функции на ООП в JS?
”
ООП е набор от принципи, които трябва да следваме, ако искаме да използваме обекти като основен начин за организиране на нашия код./Класове, правет фиилдс.
Класовете са основната езикова функция, която ни позволява да използваме ООП Те са обектни шаблони, които се използват за моделиране:
Състояние (използвайки променливи, които наричаме полета /възможност за дефолтни стойности/)
Поведение (използвайки функции, които наричаме методи) Инстанции са обектит създадени на база на класа/шаблона/”
Как можем да създадем клас, който има специфично състояние и/или поведение?
Полетата са част от данните на класа
Те са еквивалент на променливи и състоянието на обекта. Полетата могат да имат стойност по подразбиране
Методите са част от класа, и позволяват изпълнение на действие Свързаните полета и методи трябва да бъдат поставени в един и същи клас
Методите могат да взаимодействат с полетата
Създайте обект (инстанция) с помощта на клас. class Person {
name;
sayName() {
console.log(Hello I am ${this.name}
);
}
} const gosho = new Person();
gosho.name = ‘Gosho’;
gosho.sayName();
Създайте обект (инстанция) с помощта на конструктор. class Person { name;
constructor(initialName){ this.name = initialName; } sayName() { console.log(`Hello I am ${this.name}!`); } } // create instances whit constructor const gosho = new Person('Gosho'); gosho.sayName(); //implicid binding
Какво представляват инстанции на клас и как можете да създадете такъв?
Изграждане на споделен стейт или място в класовете посредством Static members за да може всяка инстанция да ги достъпи и промени посредством наименованието на класа а не посредством this. Статичните мембъри живеят с класовете до момента на спиране на програмата
“ Instatic members Свързан с instanciite (обект) Инициализира се при извикване на конструктора
Какво представляват статичните членове /статични мембъри/ и за какво се използват?
Static members Свързан с тип (клас), а не с екземпляр
Инициализира се точно преди типът да се използва за първи пътс Iзползват, когато типът трябва да има или прави конкретно нещо, което не е обвързано с нито един екземпляр Когато логиката не е обвързана с инстанциите, тя се поставя в класа като статичен мембър
class MyMath {
static pow(num: number) {
return num ** 2;
}
static abs(num: number) {
return num < 0 ? -num : num;
}
}
Статичните мембъри се извикват в самия клас. Използваме статични мембъри, за да може всички инстанции да имат достъп и/или да ги променят.
Обяснете какви са данните и защо са важни.
Компютинг процес: Целта при разработка на софтуер е той да приема чрвз инпут, обработва и запазва данните на сървър и визуализира конкретни данни. Данните са информасия или фарактеристика, която е събрана посредством софтуер или хардуер предава се на операционната система и се обработва.Данни и информация се различазват. Данните се получават в суров вид за да са информация се поставят в контекст поличаване на имена за да са ин-я трябва да знаем име на човек улица или др. Мета данни даваят конкретика за дата час ил др. Данните се репрезентират посредством променливи, които съдържат литерали. За получаване на допълнителна стойност се групират в обекти. Данните може да се предават на друг софтуер JSON XML /има много семантика/сървари. Запазване в /Persistent storage/ консистентен сторидж данни “Компютърните данни са:
Характеристики или информация
Придобити чрез хардуерен и/или софтуерен вход
Обикновено „данните“ и „информацията“ са взаимозаменяеми, но
Данните се превръщат в информация, когато се поставят в контекст
Контекстът дава значение на данните
Метаданните са данни за данни”
Създавайте обекти, които имат както състояние, така и поведение.
Обектите са съвкупност от елементи с ключ и стойност, който могът да се копират и обработват. Името на обекта персонализира данните, които се подават. В обектите може да има функционалностти, като към съответния ключ се добавя функция /наричани методи/, така обектите обединяват и групират данните с логиката в едно. ООП позволява да използваме обектите като нещо което да даде структора на кода ни По този начин свързаната логика винаги остава със свързаните данни "let person = { name: 'Lia', age: 25, getName() { return this.name; }, };
console.log(person.getName());" "Обектът е проста конструкция от двойки ключ-стойност, често наричани свойства на обекта. Обектите осигуряват лесен начин за Групиране на свързани данни Разделянето му на смислени парчета Прехвърляне на данните като цяло"
Използвайте обекти за създаване на структура в кода.
Oбектите обединяват и групират данните с логиката в едно. ООП позволява да използваме обектите като нещо което да даде структора на кода ни По този начин свързаната логика винаги остава със свързаните данни Можете директно да получите достъп до състоянието на обект чрез . person.name Можете да получите достъп до състоянието чрез метод getName() { return this.name; }," "let person = { name: 'Lili', age: 25, getName() { return this.name; }, };
console.log(person.getName());
Защитете състоянието на обекта чрез неговото поведение.
Данните са основни за вашия софтуер, трябва да са винаги във валидно (за вашия софтуер) състояние Какво ни пречи да зададем директно стойността ?
Екипните споразумение, не винаги са ефективни, при смяна на екипа или забравяне бихме имали грешки. Предотвратяване на грешки и ефективна работа на софтуера са основните причини да търсим валидация на данните” “let person3 = {
name: ‘L’,
age: 26,
setAge(newAge) { if (newAge <= 18 || newAge >= 120) { throw 'Invalid age!'; } this.age = newAge; }, }; person3.setAge(-20);" "Можете да промените състоянието директно person.age=25; Можете също да използвате метод за промяна на състоянието letperson={ name:'Ivan', age:20, setAge:function(newAge){ this.age=newAge; } } person.setAge(25);
Обяснете какво означава ключовата дума ‘this’.
Това е placeholder който получава своята стойност, когато се извика функция. Препратката, се определя от call-site , където се извиква функцията
Трябва да прегледа call-site за да определите кое от 4-те правила е приложимо. Default Binding; Implicit Binding; Explicit Binding; new Binding
“ Накратко, това не е нито препратка към самата функция, нито е препратка към лексикалния обхват на функцията.
- Какво представляват данните и защо е важно те да са валидни?
Данните са основни за вашия софтуер, трябва да са винаги във валидно (за вашия софтуер) състояние Какво ни пречи да зададем директно стойността ?
Екипните споразумение, не винаги са ефективни, при смяна на екипа или забравяне бихме имали грешки. Предотвратяване на грешки и ефективна работа на софтуера са основните причини да търсим валидация на данните
- В контекста на обектите какво е състояние и поведение?
Един обект може да има a
Състояние – данните, които обектът притежава Хората имат:
Име, което е низ
Възраст, което е число
Телефон, който може да бъде низ
Поведение – логиката, която може да се приложи към тези данни Хората могат: (поведение)
Кажете „Хей, аз съм [Име] и съм [Възраст] на години.“
Кажете „Можете да се свържете с мен на [телефон].
Какво означава ключовата дума “this”?
Това е placeholder който получава своята стойност, когато се извика функция. Препратката, се определя от call-site , където се извиква функцията
Как да определим стойността на “this”?
Explicid - Ако функцията е извикана с call()или apply() или чрез хай ордер функцията bind() Implicit Binding - Извикваме This през обект/This е във функция, която е част или се преизполлзва във конкретния обект/ ako не е Implicit or Explicid тя е Default Binding 1 This сочи към глобалния обект при използване на Node 2 This сочи към window обект при използване на браузер “const someFunc = function () {
console.log(this);
};
someFunc(); // Object [global] {
global: [Circular *1],
clearInterval: [Functio”
Кои са 4-те правила, които могат да ни помогнат да определим това? 4-те правила са. Default Binding; Implicit Binding; Explicit Binding; new Binding
- Кои са 4-те правила, които могат да ни помогнат да определим това? 4-те правила са. Default Binding; Implicit Binding; Explicit Binding; new Binding
1 Default Binding
1 Default Binding 1 This сочи към глобалния обект при използване на Node 2 This сочи към window обект при използване на браузер 3.използване на 'use strict' - undefined При използване на 'use strict' няма обръщение към глобалния обект резултата ще е undefined "const someFunc = function () { console.log(this.name); }; name = 'L' someFunc(); //L"
2 Implicit Binding;
2 Implicit Binding; Извикваме This през обект/This е във функция, която е част или се преизполлзва във конкретния обект/ " nested obj let pesho = { name: 'Pesho', sayName: sayName, };
let parent = { name: 'Lio', child: pesho, }; pesho.sayName(); //Pesho parent.child.sayName(); //Pesho" "const sayName = function () { console.log(this.name); };
let pesho = { name: 'Pesho', sayName: sayName, }; pesho.sayName(); //Pesho"
3.1 Explicit Binding;
3.1 Explicit Binding; "This все още се отнася до глобалния обхват Ние използваме .call() или apply()/при него аргумента/текста/ се подава в масив, за да зададем контекста на функциите и директно да го извикаме с този контекст" "const sayName = function () { console.log(this.name); }; const person = { name: 'Pesho', }; sayName.call(person); //Pesho" "const sayName = function (text) { console.log(`${text} ${this.name}`); }; const person = { name: 'Pesho', }; sayName.call(person, 'Hello'); //Pesho sayName.apply(person, ['Hello']);"
3.2Explicit (hard) Binding
3.2Explicit (hard) Binding “Thisвсе още се отнася до глобалния обхват
Използваме .bind() за задаване на контекста на функциите, след което можем да го съхраняваме, защото .bind() връща нова, обвързана функция” “const sayName = function () {
console.log(this.name);
};
const person = {
name: ‘Pesho’,
};
const boundSayName = sayName.bind(person);
boundSayName(); “
-Добавете структура към кода с помощта на ES модули.
Всеки клас да е в отделен файл. Създаваме person файл в който прехвърляме класа. От person class Person трябва да се експортне. В index правим импорт. За използване на ES модули с npm init създаваме package.json файл в него допълваме ""type"": ""module"", в импорта винаги добавяме екстеншъна на фаила ./person.js export class Person { import {Person} from './person.js; " "person.js export class Person { name;
constructor(initialName){ this.name = initialName; } sayName() { console.log(`Hello I am ${this.name}!`); } }" "index.js import {Person} from './person.js';
// create instances whit constructor const gosho = new Person('Gosho'); gosho.sayName();
- Назовете четирите принципа на ООП. Капсулиране Наследяване Абстракция Полиморфизъм
Капсулирането е ООП концепция, при която състоянието на обекта (полетата на класа) и неговото поведение (методи) са обвити заедно
Наследяване
Той позволява на клас да наследи състоянието и поведението на друг, по-общ клас. Например, лъвът принадлежи към биологичното семейство котки.
Абстракция
Абстракцията е нещо, което правим всеки ден. Това е действие, което прикрива всички детайли на даден обект, които не ни засягат и използва само детайлите, които са свързани с проблема, който решаваме.
Полиморфизъм
Полиморфизмът позволява третиране на обекти от производен клас като обекти на неговия основен клас. Например, големите котки (базов клас) улавят плячката си (метод) по различни начини.”
Обяснете принципа на капсулиране.
Капсулирането е концепция за ООП, при която свързано състояние (полета на клас) и поведение (методи) са групирани заедно в клас.Понякога се бърка със „скриване на информация“. Капсулирането е концепция за ООП, при която свързано състояние (полета на клас) и поведение (методи) са групирани заедно в клас. Скриването на информация е за скриване на възможно най-много вътрешни части на обекта и излагане на минимален публичен интерфейс. Тези принципи намаляват вероятността от злоупотреба с кода случайно и въвеждане на грешки.
Правете разлика между капсулиране и скриване на информация
Структурните промени остават локални:
Промяната на вътрешните елементи на класа не засяга код извън класа Промяната на прилагането на методи не отразява кода, който ги използва Скриването на подробности за внедряването намалява сложността на кода → по-лесна поддръжка Достъп до контролирано състояние Можете да добавите валидиране при промяна на стойност на поле
Можете да регистрирате събития за четене или запис на стойности на полета
- Използвайте частни полета, за да ограничите достъпа до някое състояние.
Полетата могат да бъдат маркирани като частни с #
Това означава, че имаме достъп до тях само в рамките на самия клас, но не и извън него
За разлика от използването на долната черта _, което беше само конвенция, знакът за число # е действителна езикова характеристика” “classPerson{
#name;
#age;
}
constpesho=newPerson();
pesho.#name=’XÆA-12’;
//Property’#name’isnotaccessible
“ “Полетата са членове на данни на клас
Те определят състоянието на вътрешния обект
Както знаем, трябва да запазим това състояние валидно!
Как да направим това, когато всеки може да получи достъп до полетата и да промени стойността им?
-Използвайте свойства, за да контролирате четенето и записването на състоянието.
Какво са те?
Свойства, написани като методи, но използвани като полета
Те обикновено се използват за управление на стойността на частните полета.
Поради тази причина те често се наричат по същия начин като полетата (без #)
A property се състои от две части
get – няма параметри и връща стойност
set – има един параметър и не връща стойност
Получателят и сетерът споделят едно и също име, тъй като са един член на класа” “classPerson{
#name;
getname(){
returnthis.#name;
}
setname(value){
//Validationsthis.#name=value;
}
}
“
Настройте защитено състояние, което е само за четене на кода извън класа.
Четенето на стойността на свойството извиква get част от свойството
constpesho=newPerson();
console.log(pesho.name); getname(){
returnthis.#name;
}
Записването на стойност в свойството извиква set part част от свойството constpesho=newPerson();
pesho.name=’Pesho’; setname(value){
//Validations
this.#name=value;
}
Read-only properties
Read-only properties If you create only a getter, the field will be read-only to the outside world You can still change the field value from within the class with methods " "classPerson{ #age; getage(){ returnthis.#age; } } constpesho=newPerson(); pesho.age=25; //Cannotassignto'age' " "classPerson{ #age=20; //Justsome initial value getage(){ returnthis.#age; } growOlder(){ this.#age++; } } constpesho=newPerson(); pesho.growOlder();
Write-only properties
Write-only properties If you create only a setter, the field will be write-only to the outside world You can still expose the field value using methods
classPerson{ #age=20; //Justsome initial value setage(value){ this.#age=value; } } constpesho=newPerson(); console.log(pesho.age); //Undefined (no error!)
classPerson{ #age=20; //Justsome initial value setage(value){ this.#age=value; } sayAge(){ return`Iam${this.#age}yearsold!`; } } constpesho=newPerson(); console.log(pesho.sayAge()); //Iam20yearsold!
Aggregate properties
Aggregate properties Fields and properties are not linked
A property do not have to have the same name as the field it works with
A property can also aggregate data from several fields to produce a result
You can do this with either a property or a method
classPerson{
#firstName;
#lastName;
getfullName(){
returnthis.#firstName+’‘+this.#lastName;
}
}
Always use the setters!
Always use the setters!
Validations for a field should be written in the setter
In order to use these validations in the constructor, use the property name, not the field #name!
Same goes for methods, use the property getters and setters name, not the field #name!
Be careful with name and #name
Be careful not to confuse the property and field!
Calling the property inside the same property will create an infinite loop!
" "classPerson{ #name; constructor(initialName){ this.name=initialName; } getname(){ returnthis.#name; } setname(value){ if(value===''){ thrownewError(); } this.#name=value; } }
Обяснете принципа на наследяване.
Наследяването позволява от един клас (базов / родителски) клас да се наследят ключови характеристики с помощта на думата extends Наследяват се състояние (полета и свойства)
Поведение (методи)
Детето трябва да надгражда с добавяне на нови полета, свойства или методи промяна на съществуващи членове на класа
Наследяването имплицитно приема всички членове от друг клас всички полета, методи и свойства, с изключение на частните полета, които са недостъпни
Обяснете как работи наследяването в JS.
Use inheritance for building “is-a” type of relationships
One class extends another class Дадения клас е друг по вид клас
E.g. dog is-a animal (dogs are kind of animals) Използвайте наследяване за изграждане на връзки тип “is-a” .
Един клас разширява друг клас
напр. кучето е животно (кучетата са вид животни)” “Наследяването имплицитно печели всички членове от друг клас
Всички полета, методи и свойства, с изключение на частните полета, които са недостъпни Класът, който се наследява, се нарича базов или супер клас super class
Класът, който наследява (или разширява) друг клас, се нарича производен клас derived class” “Това има много предимства
Разширяемост
Повторна употреба (повторна употреба на код)
Елиминира излишния код
Но това не винаги е отговорът
Може да внесе повече сложност, ако се използва прекомерно
Понякога е по-добре да разчитате на композицията вместо наследяването
Създайте клас, който наследява друг клас.
classPerson{ name; constructor(name){ this.name=name; } } classTeacherextendsPerson{ //Nothing here, all comes from Person} constteacher=newTeacher('Pesho'); console.log(teacher.name);//Pesho
Създайте йерархия от класове.
class BankAccount { #money depositMoney(amount)} class BankAccount { #money depositMoney(amount)} class Manager extends Employee { paySalary(employee, amount) }
”
Обяснете какво представлява композицията.
за да изградите връзка тип“has-a” , известна още като композиция Дадения клас има в себе си другия клас “Don’t use it to build “has-a” type of relationship, aka composition
One class contains another class (or some primitive type, like string) within itself in a field
E.g. dog has-a name (dog is not kind of name) Не го използвайте, за да изградите връзка тип“has-a” , известна още като композиция Дадения клас има в себе си другия клас
Един клас съдържа друг клас (или някакъв примитивен тип, като string) в себе си в поле
напр. кучето има име (кучето не е вид име)
Правете разлика между ‘is-a’ and ‘has-a’ relationships?
Използвайте наследяване за изграждане на връзки тип “is-a” . Един клас разширява друг клас . за да изградите връзка тип“has-a” , известна още като композиция
Един клас съдържа друг клас
Overriding methods
Всички методи от детето се приемат както са по подразбиране
Можете да добавите толкова нови полета, методи и свойства в детето, колкото искате
Можете да промените поведението на методите (и свойствата), които вече съществуват в родителя
Използвайте ключовата дума super за достъп до методите, свойствата и публичните полета на родителя.” “classPerson{
name;
sayName(){
returnMynameis${this.name}.
;
}
}
classTeacherextendsPerson{
subject;
sayName(){
constbaseResult=super.sayName();
returnbaseResult+Iteach${this.subject}
;
}
}
Overriding the constructor
Дъщерският клас по подразбиране взема конструктора от своя родител Подобно на методите, можете също да замените конструктора Трябва да извикате основния конструктор с помощта на super "classPerson{ name; constructor(name){ this.name=name; } } classTeacherextendsPerson{ subject; constructor(name,subject){ super(name); this.subject=subject; } }
Комбиниране на прости обекти за изграждане на по-сложни
Ползи
Разхлабен съединител
Гъвкавост
Помага да запазитевсеки клас капсулирани фокусиран върху една задача
Не винаги отговорът
Дизайн, базиран на композицията на обекта, има по-малко класове, но повече обекти
Поведението на системата ще зависи от техните взаимовръзки,вместо да бъде дефинирано в един клас
Наследяване за изграждане на „е-а“ тип взаимоотношения
Един клас разширява друг клас
Например мениджърът е служител (мениджърите са един вид служител)”
Композиция за изграждане на взаимоотношения от типа „има“.
Един клас съдържа друг клас (или някакъв примитивен тип, като низ) в себе си в поле
Например, служител има банкова сметка
Например, служителят може да депозира пари
Един клас съдържа друг клас
Служител ИМА-А банкова сметка
Състав – Служителят има (частно) поле от тип BankAccount
Служителят може да използва метода depositMoney, за да промени състоянието на сметката
Мениджър е служител
Наследяване – Мениджърът удължава служителя
Мениджърът наследява способността да депозира заплата” “class BankAccount {
#money
depositMoney(amount)} class BankAccount {
#money
depositMoney(amount)}
class Manager extends Employee {
paySalary(employee, amount)
}
Tight coupling
Tight coupling
BankAccount instance is created in the constructor - cannot be easily replaced
All employees have the same account Плътно свързване
Екземпляр на BankAccount се създава в конструктора - не може лесно да бъде заменен
Всички служители имат една и съща сметка
“ “classEmployee{#bankAccount;
constructor(name){
this.#bankAccount=newBankAccount(‘01’);
}
}
Loose coupling
BankAccount instance is received as a parameter to the constructor – can be any instance of BankAccount Employees can have different accounts " "classEmployee{#bankAccount; /**@param{BankAccount}account*/ constructor(name, account){ this.#bankAccount=account; } }
Обяснете какво са абстракция
Абстракцията фокусираме се върху необходимите детайли, запазваме само това, от което се нуждаем Кода, който пишем трябва да има състояние и поведение релевантно за проблема, който решаваме. напр. Питате за името, а не за размера на обувките напр.
Позволява ни да представим сложна реалност от гледна точка на опростен модел Абстракцията помага да се управлява сложността” “classAnimal{
makeSound(){
//Animal is an ‘abstract’ concept
//WhatdoesanAnimalsoundlike?!
thrownewError(‘Notoverridden!’);
}
} constcat=newCat();
cat.makeSound();//Meow!
constdog=newDog();
dog.makeSound();//Bark!
constanimal=newAnimal(); animal.makeSound();//Error! classCatextendsAnimal{ makeSound(){ console.log('Meow!'); } }classDogextendsAnimal{ makeSound(){ console.log('Bark!'); } }
" "classPerson{ firstName; lastName; job; } classJob{ company; position; salary; } constperson=newPerson(); person.job=newJob();
Обяснете какво е полиморфизъм.
Полиморфизмът означава ""многообразен"" Товае способността на обектите имат повече от един тип) Един клас може да се използва така, сякаш е негов родителски клас, също форма на абстракция Дъщерският клас може да отмени някои от поведенията на родителския клас. Класовете обединени в масив можем да търсим обща черта. напр. общ метод" "classAnimal{ makeSound(){ //Animal is an ‘abstract’ concept //WhatdoesanAnimalsoundlike?! thrownewError('Notoverridden!'); } } classCatextendsAnimal{ makeSound(){ console.log('Meow!'); } } classDogextendsAnimal{ makeSound(){ console.log('Bark!'); } } constcat=newCat(); cat.makeSound();//Meow! constdog=newDog(); dog.makeSound();//Bark!
constanimals=[cat,dog];
animals.forEach((animal)=>animal.makeSound()); //Meow! Bark!
Cohesion
Кохезията описва доколко методите и състоянието в един клас репрезентират една цел. Кохезията трябва да е силна
Добре дефинираните абстракции поддържат кохезията силна Кохезията трябва да е силна. Класа трябва да съдържат асно дефинирана цел.
Кохезията е мощен инструмент за управление на сложността Силен пример за сближаване
Обектът Math е със силна кохезия, той има методи: sin(), cos(), asin()
sqrt(), pow(), pxp() Math.PI, Math.E
Пример за слаба кохезия Клас, който изпълнява много несвързани задачи
Създайте документ Форматиране на документ Изпратете документа като имейл” “Strong cohesion example
The Math object that has methods:
sin(), cos(), asin()
sqrt(), pow(), pxp()
Math.PI, Math.E
Weak cohesion example Class that makes many unrelated tasks Create Document Format Document Send Document as email
Coupling
Coupling описва
Колко тясно свързани са отделните компоненти на един клас/ Компонентите не трябва да разчитат на други класове. Coupling трябва да се поддържа свободно Всички класове/функции трябва да имат малки, директни, видими и гъвкави връзки с други класове/функции /импорт експорт/ Модулите не трябва да зависят един от друг или да бъдат напълно независими (слабо свързани)
Един модул трябва да се използва лесно от други модули Разхлабен съединител
Лесно сменете стария твърд диск
Лесно поставете този твърд диск на друга дънна платка
Плътно свързване
Интегрирана видеокарта на дънна платка
Какво се случва, ако видеокартата се повреди?” “Loose Coupling
Easily replace old HDD
Easily place this HDD to another motherboard
Tight Coupling
Integrated video card on a motherboard
What happens if the video card fails?
DRY – Don’t Repeat Yourself
DRY – Don’t Repeat Yourself Този принцип е: DRY е методология за писане на код, която се отнася до дублиране на код. Това не просто увеличава обема на кода, хо предполага по трудни корекции. " "// FlowA – In some class A constusername=getUserName(); constemail=getEmail(); constuser={username,email}; client.post(user).then(/*dostuff*/); // FlowB – In another class B constusername=getUserName(); constemail=getEmail(); constuser={username,email}; client.get(user).then(/*dostuff*/); functiongetUser(){ return{ user:getUserName(), password:getPassword(), } } // FlowA client.post(getUser()).then(/*dostuff*/); // FlowB client.get(getUser()).then(/*dostuff*/);
KISS – Keep It Simple Stupid
KISS – Keep It Simple Stupid “Принципът KISS гласи че повечето системи работят най-добре, ако се поддържат прости Простотата трябва да бъде ключова цел в дизайна и ненужната сложност трябва да се избягва Това понякога може да изглежда като „нарушаване“ на други принципи. Колкото по-прост е вашият код за четене и разбиране, толкова по-лесно ще бъде да го поддържате
Другите принципи са там, за да направят кода по-лесен за разбиране и поддържане, а не по-труден!” “
Поддържането му просто изненадващо трудно
Програмирането на KISS, по-специално, е наистина важно
Ще се изкушите да напишете „хладен и гладък“ код, който не винаги е добър код
Overcomplicating in the name of ‘X’ principle
Overcomplicating in the name of ‘X’ principle Бъдете внимателни, когато следвате принципите на кода: Стриктното спазване на принципите може да доведе до прекалено сложен код; това не е просто! Понякога е по-добре да се повторите, отколкото да прекомерно проектирате кода и да го направите сложен и труден за следване. Кодовите линии не струват пари!" "// FlowA – In some class A constusername=getUserName(); constemail=getEmail(); constuser={username,email}; client.post(user).then(/*dostuff*/); // FlowB – In another class B constusername=getUserName(); constemail=getEmail(); constuser={username,email}; client.get(user).then(/*dostuff*/); functiongetUser(){ return{ user:getUserName(), password:getPassword(), } } // FlowA client.post(getUser()).then(/*dostuff*/); // FlowB client.get(getUser()).then(/*dostuff*/);
YAGNI - You Aren’t Gonna Need It
YAGNI - You Aren’t Gonna Need It Опита да мислим и кодираме някои допълнителни функции „само в случай, че имаме нужда от тях“ или смятаме че „в крайна сметка ще се нуждаем от тях“ отежнява допълнително кода.
Залагайте че „Няма да ви трябва“, това ще си спестите времето Ви и ще можете да продължите напред с проекти ефективно.
Unit Testing Definition
Единичният тест е част от код, написана от разработчик, която упражнява много малка, специфична област от функционалност на кода, който се тества За четливост - показва предвиденото практическо използване на метода/класа
За намаляване на разходите за смяна и поддръжка
За да откриете грешки по-лесно - проверете коректността на софтуера
За подобряване на дизайна на кода трябва да се направи по правилния начин
Why not to unit test?
Не знам как да пиша тестове“ „Писането на тестове е твърде трудно“ „Нямам достатъчно време да пиша тестове“ „Тестването не е моя работа“ „Кодът ми е твърде прост за тестове“ Повечето компании, които имат дълъг жизнен цикъл на разработка на софтуер, приемат някаква версия на процеса на тестване на единици.
What unit testing is not?
Тестово задвижвана разработка
Тест-първо развитие
Дизайн, управляван от тестове
Всички те разчитат на Unit Testing, но не са еднакви и не бива да се бъркат!
Тук няма да разглеждаме тези понятия, въпреки че изглеждат сравнително прости.
Manual Testing
Вече сте направили единично тестване ръчно Ръчните тестове са по-малко ефективни Не е структурирана Не се повтаря Не на целия код Не е толкова лесно, колкото би трябвало да бъде" "function sum(numbers) { return numbers.reduce((sum, current) => { sum += current; return sum; }, 0); } function sum_should(){ if (sum([1, 2]) !== 3) { throw new Error('1 + 2 !== 3’); } if (sum([-2]) !== -2) { throw new Error('-2 !== -2’); } if (sum([]) !== 0) { throw new Error('0 !== 0’); } }
Unit Testing
Тестовете са специфични парчета код
В повечето случаи те са написани от разработчици, а не от QA инженери
Единичните тестове се пускат в кодовото хранилище
Рамките за тестване на модули опростяват много процеса
Jest, Mocha, Jasmine и др.
What to test?
Всички класове трябва да бъдат тествани
Всички методи трябва да бъдат тествани
Тривиалният код може да бъде пропуснат -> напр. придобиващи и задаващи свойства
Частните методи могат да бъдат пропуснати -> някои гурута препоръчват никога да не ги тествате
В идеалния случай всички тестове за модули трябва да преминат, преди да бъдат натиснати в хранилището за контрол на източника
What makes a good Unit Test?
Работи бързо Автоматизиран е и се повтаря Лесен е за изпълнение Актуално е за утре Последователен е в резултатите си Има пълен контрол над тествания уред Напълно изолиран
What makes a good Unit Test?
Когато не успее, трябва да бъде лесно да се открие какво се очаква и да се определи как да се определи проблема.
Всеки трябва да може да го стартира с натискане на бутон.
What makes a good Unit Test?
Работи бързо Автоматизиран е и се повтаря Лесен е за изпълнение Актуално е за утре Последователен е в резултатите си Има пълен контрол над тествания уред Напълно изолиран Когато не успее, трябва да бъде лесно да се открие какво се очаква и да се определи как да се определи проблема.
Всеки трябва да може да го стартира с натискане на бутон.
When should we remove or change a test?
По принцип минаващият тест никога не трябва да се премахва
Тези тестове гарантират, че промените в кода не нарушават работещия код
Тестът за преминаване трябва да бъде променен само, за да стане по-четлив
Неуспешният тест трябва да бъде проверен, за да се провери дали отговаря на изискванията
Tests should reflect reality
Tests are the single point of truth for your application
What’s wrong here?
A failing test should prove that there is something wrong with the production code, not with the unit test code
"it('add one and two', () => { const result = sum([1, 2]);
expect(result).toBe(4);
});
Code Assertions
Code Assertions Generally, avoid multiple asserts in a single test case
But only if the asserts belong logically to another test
If any of the assertions fails, the test will also fail
“it(‘test sum’, () => {
expect(sum([1, 2])).toBe(3);
expect(sum([-2])).toBe(-2);
expect(sum([])).toBe(0);
});