Відповіді на 12 основних питань з JavaScript

21

Від автора: ці питання JavaScript ставлять у безвихідь навіть досвідчених розробників. JS – дивовижний і гнучкий інструмент веб-дизайну. Але навіть у самих великих інструментах завжди є чому вчитися. Нижче представлені 12 запитань і відповідей) по JS, які ставлять в безвихідь безліч розробників, навіть досвідчених JS програмістів.

На першій сторінці ми розглянемо основні питання і відповіді, в тому числі, які часто траплялися на співбесідах. На другій сторінці ми більш докладно розберемо дві більш складні області: як за допомогою JS поліпшити продуктивність сайту і як убезпечити код в довгостроковій перспективі.

1. Що таке прототипних спадкування і в чому його користь?

В JS майже всі являє собою об’єкт. У кожного об’єкта є прототип, від якого він успадкував значення і поведінку. Якщо об’єкт не включає запитувана властивість, JS зробить його пошук всередині прототипу. Пошук триває по ланцюжку прототипів, поки не буде знайдено властивість. В іншому випадку повернеться помилка.

Корисна функція при створенні об’єктів, які ділять значення і операції. Вони живуть у прототипі, тому потрібна тільки одна копія, що покращує використання пам’яті в проектах.

var parent = {inherit: true}
var childA = Object.create(parent);
var childB = {};
Object.setPrototypeOf(childB, parent);
class childC extends parent {}

Прототип можна додати в об’єкт при його створенні за допомогою Object.create() або після створення за допомогою Object.setPrototypeOf(). У ES2015 є ключове слово class, яке в парі з extends буде використовувати це значення, як його прототип.

2. Як за допомогою JS можна поліпшити доступність?

Сучасні інструменти доступності здатні обробляти JS і динамічний контент. Їх можна використовувати в якості помічників цим технологіям, поки вони використовуються, як поліпшення, а не потрібні для роботи.

Поширений спосіб допомогти користувачам – це забезпечити корисне управління фокусом. Календар, наприклад, повинен перемикатися між днями за допомогою стрілок, а клавіші вгору і вниз повинні перемикати тижня. Для цього необхідно просто стежити за подіями клавіатури, поки фокус знаходиться всередині цього компонента.

Зміна важливих даних за допомогою JS (наприклад, зворотний зв’язок) має анонсуватися в скрін рідерах. Найчастіше така поведінка досягається шляхом позначення контейнера, як живий області.

3. Що таке спливання події, і чим воно відрізняється від перехоплення події?

Відповіді на 12 основних питань з JavaScript

Делегування подій – техніка, що використовує спливання подій в своїх інтересах. Додавши обробник на батьківський елемент, розробники будуть знати про спрацювання подій будь-якого дочірнього елемента.

Перехоплення події і спливання події – частини процесу «поширення подій», в якому браузери відповідають на спрацьовування подій на сторінці. Старі браузери вміють або те, або інше. Зараз же браузери вміють і те і те.

Перший етап – етап перехоплення – виникає, як тільки спрацьовує подія. Він починається на самому верхньому рівні (тобто document або window залежно від події). Зверху він йде вниз через і інші теги і досягає елемента, всередині якого виникло подія.

Слідом запускається другий етап – етап спливання. Він повторює процес, але вже у зворотному порядку, починаючи з елемента, на якому відбулася подія, і «спливаючи» до елемента верхнього рівня html. При додаванні обробників подій така поведінка стоїть за умовчанням.

4. Як делегування подій покращує код на сайтах з великою кількістю інтерактивних елементів?

На веб-сайтах часто маса динамічного контенту, який постійно змінюється. Якщо ці елементи повинні бути інтерактивними, вам будуть потрібні деякого роду обробники подій, підхоплюючі ці взаємодії. Якщо на кожен елемент створювати свій обробник події, це захарастить код і збільшить кількість елементів, за якими браузер зобов’язаний стежити.

Делегування подій – техніка, що використовує спливання подій на свою користь. Додавши обробник до батьків, розробники отримують сповіщення про події на його дочірніх елементах.

parentEl.addEventListener. (‘click’, function(e) {
if(e.target && e.target.вузла == ‘BUTTON’) {
// Button clicked
} });

Всередині колбек-функції події оригінальна мета завжди буде target. З її допомогою можна вирішувати, що робити далі. Наприклад, data-атрибут може зберігати ID, щоб посилатися на властивість об’єкта.

5. Що таке замикання і чим вони корисні в організації коду?

Функції JS використовують так звану «лексичну середу», тобто в них є доступ до змінних, визначеним ззовні, але доступ до змінних, заданих межах, можна отримати тільки зсередини.

function outer() {
нехай x = ‘Web Designer’;
function shout() {
alert(`I love ${x}!`);
}
shout(); }

Виклик outer() поверне «I love Web Designer!», але якщо посилатися на shout або x не з outer(), і змінна і функція будуть не визначені. Замикання являє собою функцію разом з її лексичної середовищем. У нашому випадку замиканням буде функція outer.

Замикання корисні при створенні декількох компонентів, так як що-небудь, оголошене всередині, не вплине на інший код. З їх допомогою можна створювати приватні функції та змінні, як в ООП мовах типу Python. Шаблон модуля активно використовує замикання для створення структурованих способів взаємодії з модулями.

6. Що значить «use strict» перед блоком коду?

ES5 представив необов’язковий варіант SJ під назвою strict mode. У строгому режимі примхи більш ранніх версій будуть викидати помилки замість непередбачуваної поведінки.

function strictFunction() {
‘use strict’;
myVar = 4; //ReferenceError }

Вище ми отримуємо доступ до неіснуючої змінної. У спрощеному режимі myVar буде додана в глобальний простір видно, що при необережному використанні може переписати раніше певну функціональність скрипта. У строгому режимі вилетить помилка, що запобігає будь-які руйнування. Модулі ES2015 знаходяться у суворому режимі за замовчуванням, однак у замиканнях, створених за допомогою функцій, use strict може застосовуватися на функціональному рівні, а також до всього файлу.

7. Що означає термін hoisting по відношенню до JS?

JS унікальна в тому плані, що його не треба компілювати перед розподілом. Браузер скомпилирует скрипти як тільки знайде їх і зробить записи про будь функції та змінної, оголошеної всередині.

Потім браузер виконує код, знаючи, де ці функції і змінні застосувати. Як тільки блок виконаний, його функції та змінні «піднімаються» у верхню частину блоку.

welcome(«Matt»); //»Welcome, Matt.»
function welcome(name) {
return `Welcome, ${name}.`;
}

У цьому прикладі ми можемо використовувати функцію welcome, так як вона піднімається у верхню частину скрипта.

8. У чому різниця між стрілочної і звичайною функцією?

ES2015 представив безліч змін, і одне з них – швидке вплив на стрілочні функції.

function CountUp() {
this.x = 0;
setInterval(() => console.log(++this.x), 1000); }
var a = new CountUp();

Ключова відмінність, крім більш короткої форми запису, в тому, що стрілочний функції не створюють своє значення для this. Замість цього вони використовують значення замикаючого блоку. В приклад вище в лог виведеться 1, 2, 3 і т. д. кожну секунду. У звичайній функції this.x буде undefined, і в лог виведеться NaN. Тіло стрілочної функції буде її обчислене значення. Це робить стрілочні функції корисними для промисов, через які передаються значення. Звичайні функції зобов’язані явно повертати значення, в іншому випадку повернеться undefined.

9. Де потрібно використовувати ключові слова let const і замість var?

Ще одна фундаментальна зміна в ES2015 – з’явилися let та const – альтернативні способи створення змінних. Оголошені таким способом змінні обмежені блоком, в якому оголошено. Це робить більш чітке розділення між блоками (код різних блоків не буде впливати один на одного).

for(let x=1; x<=3; x++) {
console.log(x); // 1, 2, 3}
console.log(x); // «x is not defined»

Якщо значення змінної не буде змінюватися, використовуйте const замість let. При спробі змінити константу буде викинута помилка. Об’єкти та масиви все ще можна змінювати всередині, але повністю вони не замінюються.

Let та const не «піднімаються» як var, тобто на них не можна посилатися перед ініціалізацією. Область між початком блоку і називається ініціалізацією «тимчасова мертва зона». Найчастіше вона може вводити в ступор.

10. Що таке функціональне програмування, і в чому його відмінність?

Відповіді на 12 основних питань з JavaScript

Це альтернативний спосіб створення програм шляхом передачі стану додатки виключно через функції. Уникаючи побічних ефектів, можна розробити легко розуміється код.

Зазвичай, JS проекти побудовані за структурою ООП. Інформація про поточний стан програми зберігається всередині об’єктів, які оновлюються зі зміною сторінки.

Функціональне програмування дає інший спосіб мислення. Мови типу F# користуються даним підходом вже досить давно, проте ES2015 приніс важливі методи в JS і відкрив їх вебу.

Вся робота виконується всередині «чистих» функцій. Це функції, що не порушувалися даними будь-якого роду зовні області видимості функції. Іншими словами, якщо передавати у функцію одні і ті ж значення, повертатися буде завжди однаковий результат.

Це так само означає, що між такими функціями не може бути загальних станів. Будь-який стан усередині додатку, який необхідно використовувати, не повинно викликатися безпосередньо і повинно бути передано в функцію у вигляді параметра.

Код повинен уникати зміни значень після їх отримання. Наприклад, кожна зміна об’єкта повинна повертати копію об’єкта зі зміненим змістом. Це робиться, щоб уникнути побічних ефектів, які можуть викликати баги і ускладнити тестування коду.

11. Як за допомогою JS поліпшити продуктивність сайту?

У часи, коли більша частина веба проглядається через мобільні пристрої та планшети, продуктивність відіграє критичне значення. Не у всіх новітнє пристрій, і кожна затримка і посмикування можуть коштувати вам покупця. На щастя, існує безліч способів на JS, як цього уникнути.

Зберігаємо пасивність

Надмірна прокрутка – явна ознака того, що щось відбувається. У деяких випадках браузер змушений чекати, так як обробники звертаються до сторінки. Події типу wheel і touchmove здатні скасовувати прокручування, тому сторінка повинна чекати, поки подія не завершиться до початку прокрутки.

Це викликає дерганое і нестандартна поведінка при прокручуванні, що виливається в поганій UX.

document.addEventListener. (‘touchmove’, handler, {passive: true});

Щоб уникнути цього, передайте об’єкт в якості третього параметра при додаванні обробника події. Помітивши подія пасивним, браузер думає, що прокрутка нічому не завадить, тому її можна почати відразу ж.

Третій параметр замінює опцію useCapture в старих браузерах, тому важливо використовувати виявлення функцій при використанні обробників даного типу. Для навмисного відключення прокручування в більшості браузерів допоможе запис в CSS touch-action: none.

Події перевірки

Події типу прокрутки і зміни розміру запускаються максимально швидко, щоб обробник завжди оновлювався. Якщо на кожному подію відбувається щось ресурсномістке, це може швидко заморозити сторінку.

const resizeDebounce = debounce(() => {
// Code for resize event }, 200);
window.addEventListener. (‘resize’, resizeDebounce);

Debouncing – техніка, перевіряє як часто на одне з подій викликається колбек. Реалізація функції debounce і того, як часто викликається функція, відрізнятиметься від проекту до проекту, але зменшення подій до 5 в секунду, наприклад, відразу ж поліпшити продуктивність сторінки.

Фокус на вьюпорте

Зазвичай подія scroll використовується для визначення моменту потрапляння елемента в полі зору сторінки. Навіть з debouncing виклик getBoundingClientRect вимагає від браузера повторного аналізу макета сторінки. Є новий браузерний API IntersectionObserver, який говорить про видимості елементу, викликаючи функцію, коли елемент потрапляє або зникає з вьюпорта. Для сайтів з нескінченним скролом це можна використовувати як прапор для видалення або оновлення старої вистави.

IntersectionObserver доступний у всіх останніх браузерах окрім Safari. Варто використовувати цей API і фолбеком старих техніки, так як різниця дуже помітна.

Відокремлюйте витратну роботу

При роботі з великими обсягами даних або обробці великих файлів зображень JS може швидко заморозити вікно браузера. Вся робота виконується на одній гілці. Якщо лінія зайнята, інтерфейс не можна оновити.

Якщо ви знаєте, що процес займе багато часу, його добре б помістити на веб-воркер. Ці скрипти запускаються в окремій гілці, яка не зачіпає роботу інтерфейсу. Скрипти можуть спілкуватися один з одним через спеціальний метод повідомлень. Веб-воркеры не мають доступу до DOM і деяким властивостям об’єкта window. З допомогою цих повідомлень можна передавати необхідну інформацію.

12. Як я можу захистити свій JS код в довгостроковій перспективі?

Один з базових принципів JS – JS завжди намагається уникати ламають змін там, де це можливо. Велика частина написаного сьогодні коду буде працювати і через десять років, незважаючи на постійно мінливу індустрію.

Якщо блок коду запускається, це не говорить про те, що він буде запускатися в майбутньому. Чи буде ваш код працювати через пару років?

Уникайте спагетті коду

У першому проекті у вас може виникнути бажання писати все в одному місці. Так явно видно, що робить кожен блок коду, але це також пов’язує всі поведінку. Якщо в іншій області проекту знадобиться цей функціонал, його доведеться копіювати, переписувати. Якщо буде знайдений баг, або додана нова функція, необхідно буде оновлювати версії, що може відняти багато часу.

Зберігаючи модульність коду, ви можете підключати функціональність там, де вона необхідна. Після написання відразу доступні будь-які зміни. Техніки модульного типу шаблону можуть бути реалізовані без впливу на решті проект, що полегшує їх створення.

Не використовуйте фреймворки

Безліч сучасних фреймворків типу React або Polymer радять розробникам зберігати все в модулях через створення компонентів. Кожен компонент може по-своєму спілкуватися з іншими частинами проекту.

Що робити, коли вийде наступний кращий фреймворк? Переходити на нього або навіть просто оновлення може бути досить складним завданням. Пошук нових способів оживити старі компоненти може з’їсти багато часу.

По можливості використовуйте стандартні JS функції. Таким чином, при зміні фреймворків ви мінімізуєте ризики. Наприклад, використовуйте об’єкти для обробки маніпуляцій з даними перед їх передачею в компонент.

Це також допомагає при написанні універсального JS. По можливості не використовуйте браузерні API, так код можна буде повторно використовувати як в браузері, так і на сервері в Node.

Прибирайте

Як тільки модулі написані підтримуйте в них чистоту. Будь читаючий повинен розуміти функціональність для прискорення дебага.

let activeUsers = users.filter(user => user.active === true);

Самодокументирующий код – потужний інструмент захисту коду на майбутнє. Описові імена змінних ітераторів, наприклад, спростять читання, на відміну від стандартного i.

Найголовніше, будьте послідовні. Дотримуючись одного стилю коду, ви надаєте йому читаності. Визначайте загальний вигляд коду з допомогою стильових гідів і застосовуйте його з допомогою ESLint.

Працюйте на масштаб

Читаність також поширюється на структуру проекту. Без неї все швидко заплутається.

При роботі над першим проектом зберігання всіх файлів в одній папці спрощує роботу. Коли скрипти імпортують модулі, вам відразу зрозуміло, де вони розташовані.

З розростанням проекту великі колекції файлів можуть загубитися в масі. Підтримуйте добре масштабовану структуру. Зберігайте всі модулі, що працюють з користувачами, папки users, наприклад. Звичайно ж, ідеальна структура залежить від проекту. Для односторінкового додатки зберігання моделі, подання та контролера окремо – обов’язкова вимога.

Підтримуйте тестованість

Відповіді на 12 основних питань з JavaScript

Фреймворки типу React радять створювати маленькі, повторно використовувані компоненти. Навіть у масштабній структурі проекту може бути складно перевірити їх роботу. Написавши тести, проект можна розгортати з упевненістю.

Юніт тести будуть працювати на модульному рівні. Інструменти типу Mocha і Jest дозволяють розроблювачам визначати очікуваний висновок для заданого набору. Періодично запускайте ці тести, щоб уникнути сторонніх ефектів.

Модулі повинні писатися так, щоб їх можна було тестувати ізольовано. Тобто потрібно якомога менше зовнішніх залежностей, і не можна покладатися на глобальний стан.

Також є інтеграційне і функціональне тестування. Воно повинно максимально покривати додаток, щоб код довго працював.

Мова завтрашнього дня

Відповіді на 12 основних питань з JavaScript

Кращий спосіб убезпечити код – писати його на синтаксисі майбутнього. Це може здатися кроком у невідоме, проте є інструменти максимально спрощують цей процес.

Babel – транспайлер, інструмент, конвертирующий одну форму JS в іншу. Його використовують для перетворення сучасного коду у формати для старих браузерів і оточення.

ES2015 багато додала в JS щодо чистоти коду. Наприклад, стрілочні функції, промисы та нативні модулі. Останній стандарт ES2017 принесе ще більше зручностей, завдяки асинхронним функцій. Babek вміє конвертувати весь цей код, щоб використовувати його вже сьогодні.

Зрештою, проекти зможуть взагалі пропускати крок транспиляции. Але зараз він необхідний для захисту коду.