3 въпроса за JavaScript, за които да внимавате по време на интервюта за кодиране

JavaScript е официалният език на всички съвременни уеб браузъри. Като такива, въпроси за JavaScript се появяват във всякакви интервюта за разработчици.

Тази статия не е за най-новите библиотеки на JavaScript, общи практики за разработка или някоя от новите функции на ES6. По-скоро става въпрос за 3 неща, които обикновено се появяват в интервюта, когато се обсъжда JavaScript. На мен самите са ми задавали тези въпроси и приятелите ми са ми казвали, че и тях са им задавали.

Разбира се, това не са единствените 3 неща, които трябва да изучите преди интервю за JavaScript - има множество начини, по които можете да се подготвите по-добре за предстоящо интервю - но по-долу има 3 въпроса, които интервюиращият може да зададе, за да прецени колко добре знаете и разбирате езика JavaScript и DOM.

Така че нека да започнем! Обърнете внимание, че ще използваме ванилов JavaScript в примерите по-долу, тъй като интервюиращият ви обикновено иска да види колко добре разбирате JavaScript и DOM без помощта на библиотеки като jQuery.

Въпрос №1: Делегиране на събитие

Когато изграждате приложение, понякога ще трябва да прикачите слушатели на събития към бутони, текст или изображения на страницата, за да извършите някакво действие, когато потребителят взаимодейства с елемента.

Ако вземем за пример прост списък със задачи, интервюиращият може да ви каже, че иска да се извърши действие, когато потребителят щракне върху един от елементите в списъка. И те искат да внедрите тази функционалност в JavaScript, като приемете следния HTML код:

  • Walk the dog
  • Pay bills
  • Make dinner
  • Code for one hour

Може да искате да направите нещо като следното, за да прикачите слушатели на събития към елементите:

document.addEventListener('DOMContentLoaded', function() { let app = document.getElementById('todo-app'); let items = app.getElementsByClassName('item'); // attach event listener to each item for (let item of items) { item.addEventListener('click', function() { alert('you clicked on item: ' + item.innerHTML); }); } });

Въпреки че това технически работи, проблемът е, че прикачвате слушател на събития към всеки отделен елемент поотделно. Това е добре за 4 елемента, но какво, ако някой добави 10 000 елемента (може да има много неща за вършене) към списъка си с задачи? Тогава вашата функция ще създаде 10 000 отделни слушатели на събития и ще прикачи всеки от тях към DOM. Това не е много ефективно.

В интервю би било най-добре първо да попитате интервюиращия какъв е максималният брой елементи, които потребителят може да въведе. Ако никога не може да бъде повече от 10, например, тогава горният код ще работи добре. Но ако няма ограничение за броя елементи, които потребителят може да въведе, тогава бихте искали да използвате по-ефективно решение.

Ако вашето приложение може да завърши със стотици слушатели на събития, по-ефективното решение би било всъщност да прикачите един слушател на събития към целия контейнер и след това да имате достъп до всеки елемент, когато всъщност е щракнат. Това се нарича делегиране на събития и е много по-ефективно от прикачването на отделни манипулатори на събития.

Ето кода за делегиране на събития:

document.addEventListener('DOMContentLoaded', function() { let app = document.getElementById('todo-app'); // attach event listener to whole container app.addEventListener('click', function(e) { if (e.target && e.target.nodeName === 'LI') { let item = e.target; alert('you clicked on item: ' + item.innerHTML); } }); });

Въпрос №2: Използване на затваряне в рамките на цикъл

Понякога се затварят в интервю, за да може интервюиращият да прецени доколко сте запознати с езика и дали знаете кога да приложите закриване.

Затварянето е основно, когато вътрешна функция има достъп до променливи извън обхвата си. Затварянията могат да се използват за неща като внедряване на поверителност и създаване на фабрики за функции. Често срещан въпрос за интервю относно използването на затваряне е нещо подобно:

Напишете функция, която ще премине през списък с цели числа и ще отпечата индекса на всеки елемент след 3 секундно закъснение.

Често срещано (неправилно) изпълнение, което видях за този проблем, изглежда по следния начин:

const arr = [10, 12, 15, 21]; for (var i = 0; i < arr.length; i++) { setTimeout(function() { console.log('The index of this number is: ' + i); }, 3000); }

Ако стартирате това, ще видите, че всъщност получавате 4 отпечатани всеки път вместо очакваните 0, 1, 2, 3 след 3 секундно закъснение.

За да се идентифицира правилно защо това се случва, би било полезно да се разбере защо това се случва в JavaScript, което е точно това, което интервюиращият се опитва да тества.

Причината за това е, защото setTimeoutфункцията създава функция (затварянето), която има достъп до външния си обхват, който е цикълът, който съдържа индекса i. След 3 секунди функцията се изпълнява и тя отпечатва стойността на i, която в края на цикъла е на 4, тъй като преминава през 0, 1, 2, 3, 4 и накрая цикълът спира на 4.

Всъщност има няколко начина за правилно писане на функцията за този проблем. Ето два от тях:

const arr = [10, 12, 15, 21]; for (var i = 0; i < arr.length; i++) { // pass in the variable i so that each function // has access to the correct index setTimeout(function(i_local) { return function() { console.log('The index of this number is: ' + i_local); } }(i), 3000); }
const arr = [10, 12, 15, 21]; for (let i = 0; i < arr.length; i++) { // using the ES6 let syntax, it creates a new binding // every single time the function is called // read more here: //exploringjs.com/es6/ch_variables.html#sec_let-const-loop-heads setTimeout(function() { console.log('The index of this number is: ' + i); }, 3000); }

Въпрос №3: Разобличаване

Има някои събития в браузъра, които могат да се задействат много пъти в рамките на кратък период от време много бързо, като например преоразмеряване на прозорец или превъртане на страница надолу. Ако например прикачите слушател на събитие към събитието за превъртане на прозореца и потребителят непрекъснато превърта надолу страницата много бързо, вашето събитие може да се задейства хиляди пъти в рамките на 3 секунди. Това може да доведе до някои сериозни проблеми с производителността.

Ако обсъждате изграждането на приложение в интервю и се появят събития като превъртане, преоразмеряване на прозореца или натискане на клавиш, не забравяйте да споменете отмяна и / или регулиране като начин за подобряване на скоростта и производителността на страницата. Истински пример, взет от тази публикация за гости на css-tricks:

През 2011 г. на уебсайта на Twitter се появи проблем: когато превъртате надолу вашата емисия в Twitter, той стана бавен и не реагира. Джон Резиг публикува публикация в блога за проблема, където се обяснява колко лоша е идеята да се прикачат директно скъпи функции към scrollсъбитието.

Обезличаването е един от начините за решаване на този проблем чрез ограничаване на времето, което трябва да премине, докато дадена функция не бъде извикана отново. Правилното прилагане на debouncing би затова групови няколко извиквания на функции в един и да го изпълни само веднъж след като е изтекло известно време. Ето реализация в обикновен JavaScript, която използва теми като обхват, затваряния, това и събития за синхронизация:

// debounce function that will wrap our event function debounce(fn, delay) { // maintain a timer let timer = null; // closure function that has access to timer return function() { // get the scope and parameters of the function // via 'this' and 'arguments' let context = this; let args = arguments; // if event is called, clear the timer and start over clearTimeout(timer); timer = setTimeout(function() { fn.apply(context, args); }, delay); } }

Тази функция - когато е увита около събитие - ще се изпълнява само след изтичане на определен период от време.

Можете да използвате тази функция по следния начин:

// function to be called when user scrolls function foo() { console.log('You are scrolling!'); } // wrap our function in a debounce to fire once 2 seconds have gone by let elem = document.getElementById('container'); elem.addEventListener('scroll', debounce(foo, 2000));

Throttling е друга техника, която е подобна на debouncing, с изключение на това, че вместо да изчакате да мине известно време, преди да извикате функция, дроселирането просто разпределя повикванията на функцията в по-дълъг интервал от време. Така че, ако дадено събитие се случи 10 пъти в рамките на 100 милисекунди, регулирането може да разпръсне всяко от извикванията на функцията, което да се изпълнява веднъж на всеки 2 секунди, вместо да изстреля в рамките на 100 милисекунди.

За повече информация относно оттеглянето и регулирането, следните статии и уроци могат да бъдат полезни:

  • Дроселиране и отстраняване на грешки в JavaScript
  • Разликата между дроселиране и отпадане
  • Примери за дроселиране и обезкосмяване
  • Пост в блога на Реми Шарп за повиквания на функцията за регулиране

If you enjoyed reading this article, then you may like reading the JavaScript tutorials and solving some of the JavaScript coding challenges that I host on Coderbyte. I’d love to hear what you think!