Вам бонус- начислено 1 монета за дневную активность.
Сейчас у вас 1 монета
Вопросы и ответы на собеседования frond-end разработчика Javascript
Лекция
Привет, сегодня поговорим про ответы на собеседования frond-end разработчика javascript, обещаю рассказать все что знаю. Для того чтобы лучше понимать что такое
ответы на собеседования frond-end разработчика javascript , настоятельно рекомендую прочитать все из категории Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend).
1. Как можно оптимизировать загрузку внешних ресурсов на странице?
Конкатенация
Минификация
Использование CDN
Кеширования
и т.д.
2 Каково преимущество в подгрузке внешних ресурсов с нескольких доменов?
Сколько ресурсов браузер может одновременно качать с одного домена?
3 Назовите три способа уменьшения времени загрузки страницы (воспринимаемого или реального)
Какие инструменты Вы используете для тестирования производительности кода?
JSPerf (http://jsperf.com/)
Dromaeo (http://dromaeo.com/)
и т.д.
Что такое FOUC (Flash Of Unstyled Content)? Как его избежать?
Расскажите о своей среде разработки (ОС, редактор, браузер(ы), прочие инструменты)
Опишите последовательность Ваших действий, когда вы создаете новую Web-страницу
Объясните различие между
<script>, <script async> и <script defer>
Опишите нижеперечисленные заголовки запросов и откликов:
Различие между: — Expires, Date, Age и If-Modified-… — DNT — Cache-Control — Transfer-Encoding — ETag — X-Frame-Options
[⬆] Вопросы по JavaScript:
Какими js-библиотеками Вы пользовались?
Вы когда-нибудь заглядывали в исходный код библиотек/фреймворков, которыми пользовались?
Чем JavaScript отличается от Java?
Что-такое хэш-таблица?
Что такое неопределенные (undefined) и необъявленные (undeclared) переменные?
Что такое замыкание и как/для чего его используют?
Как вы предпочитаете их использовать?
Где обычно используются анонимные функции?
Объясните "JavaScript module pattern" и где он (паттерн) применяется
Бонус, если упомянута чистота глобального пространства имен
Что, если Ваш модуль не заключен в пространство имен?
Как Вы организуете свой код? (module pattern, наследование)
В чем разница между host-объектами и нативными объектами?
В чем разница между последними двумя строчками:
function Person(){}
var person = Person()
var person = new Person()
В чем разница между .call и .apply?
Что делает и для чего нужна функци Function.prototype.bind?
Когда Вы оптимизируете свой код?
Объясните, как работает наследование в JavaScript?
Где до сих пор используется document.write()?
В большинстве генерируемых баннеров, хотя так делать не рекомендуется
В чем разница между feature detection (определение возможностей браузера), feature inference (предположение возможностей) и анализом строки user-agent?
Расскажите об AJAX как можно более подробно
Объясните, как работает JSONP (и почему это не настоящий AJAX)
Вы когда-нибудь использовали шаблонизацию на JavaScript?
Если да, какие библиотеки использовали? (Mustache.js, Handlebars etc.)
Объясните, что такое "hoisting"
Объясните event bubbling
В чем разница между "атрибутом" (attribute) и "свойством" (property)?
Почему не следует расширять нативные JavaScript объекты?
Почему следует расширять нативные JavaScript объекты?
В чем разница между событиями document load и document ready?
В чем разница между == и ===?
Как получить параметры из URL'а текущего окна?
Объясните same-origin policy в контексте JavaScript
Объясните event delegation
Какие Вы знаете паттерны организации наследования в JavaScript?
Опишите принцип мемоизации (избежание повторных вычислений) в JavaScript
Почему тернарный оператор так называется?
Что такое арность функции?
Что делает строчка "use strict";? Какие достоинства и недостатки от ее использования?
[⬆] Примеры кода на JavaScript
~~3.14
Вопрос: Какое значение возвращает данное предложение? Ответ: 3
"i'm a lasagna hog".split("").reverse().join("");
Вопрос: Какое значение возвращает данное предложение? Ответ: "goh angasal a m'i"
( window.foo || ( window.foo = "bar" ) );
Вопрос: Чему равно window.foo? Ответ: "bar", только если выражение window.foo было ложным, иначе переменная сохранит свое изначальное значение
var foo = "Hello"; (function() { var bar = " World"; alert(foo + bar); })(); alert(foo + bar);
Вопрос: Что покажут эти два alert? Ответ: "Hello World" и ReferenceError: bar is not defined
var foo = [];
foo.push(1);
foo.push(2);
Вопрос: Чему равно foo.length? Ответ: 2
var foo = {};
foo.bar = 'hello';
Вопрос: Чему равно foo.length? Ответ: undefined
[⬆] Вопросы по jQuery:
Объясните "chaining".
Объясните "deferreds".
Какие Вы знаете приемы оптимизации кода, использующего jQuery?
Что делает .end()?
Как добавить пространство имен к обработчику событий? Для чего это нужно?
Назовите 4 разных вида аргументов, которые принимает функция jQuery()?
Селектор (строка), HTML (строка), Callback (функция), HTMLElement, объект, массив, массив элементов, объект jQuery etc.
Что такое очередь эффектов (fx queue)?
В чем разница между .get(), [], и .eq()?
В чем разница между .bind(), .live(), и .delegate()?
В чем разница между $ и $.fn? Что вообще такое $.fn?
Оптимизируйте данный селектор:
$(".foo div#bar:eq(0)")
напишите пример замыкания на JavaScript
Если вы используете JavaScript, но при этом так до конца и не разобрались, что же это за чудная штука такая —замыкания, и зачем она нужна — эта статья для вас.
Как известно, в JavaScript областью видимости локальных переменных (объявляемых словом var) является тело функции, внутри которой они определены.
Если вы объявляете функцию внутри другой функции, первая получает доступ к переменным и аргументам последней:
function outerFn(myArg) { var myVar; function innerFn() { //имеет доступ к myVar и myArg } }
При этом, такие переменные продолжают существовать и остаются доступными внутренней функцией даже после того, как внешняя функция, в которой они определены, была исполнена.
Рассмотрим пример — функцию, возвращающую кол-во собственных вызовов:
function createCounter() { var numberOfCalls = 0; returnfunction() { return ++numberOfCalls; } } var fn = createCounter(); fn(); //1 fn(); //2 fn(); //3
В данном примере функция, возвращаемая createCounter, использует переменную numberOfCalls, которая сохраняет нужное значение между ее вызовами (вместо того, чтобы сразу прекратить свое существование с возвратом createCounter).
Именно за эти свойства такие «вложенные» функции в JavaScript называют замыканиями (термином, пришедшим из функциональных языков программирования) — они «замыкают» на себя переменные и аргументы функции, внутри которой определены.
Применение замыканий
Упростим немножко пример выше — уберем необходимость отдельно вызывать функцию createCounter, сделав ее аномимной и вызвав сразу же после ее объявления:
var fn = (function() { var numberOfCalls = 0; returnfunction() { return ++ numberOfCalls; } })();
Такая конструкция позволила нам привязать к функции данные, сохраняющиеся между ее вызовами — это одно из применений замыканий. Иными словами, с помощью них мы можем создавать функции, имеющие свое изменяемое состояние.
Другое хорошее применение замыканий — создание функций, в свою очередь тоже создающих функции — то, что некоторые назвали бы приемом т.н. метапрограммирования. Например:
Благодаря замыканию возвращаемая функция «запоминает» параметры, переданные функции создающей, что нам и нужно для подобного рода вещей.
Похожая ситуация возникает, когда мы внутреннюю функцию не возвращаем, а вешаем на какое-либо событие — поскольку событие возникает уже после того, как исполнилась функция, замыкание опять же помогает не потерять переданные при создании обработчика данные.
Рассмотрим чуть более сложный пример — метод, привязывающий функцию к определенному контексту (т.е. объекту, на который в ней будет указывать слово this).
Function.prototype.bind = function(context) { var fn = this; returnfunction() { return fn.apply(context, arguments); }; } var HelloPage = { name: 'Habrahabr', init: function() { alert('Hello, ' + this.name); } } //window.onload = HelloPage.init; //алертнул бы undefined, т.к. this указывало бы на window window.onload = HelloPage.init.bind(HelloPage); //вот теперь все работает
В этом примере с помощью замыканий функция, вощвращаемая bind'ом, запоминает в себе начальную функцию и присваиваемый ей контекст.
Следующее, принципиально иное применение замыканий — защита данных (инкапсуляция). Рассмотрим следующую конструкцию:
(function() { … })();
Очевидно, внутри замыкания мы имеем доступ ко всем внешним данным, но при этом оно имеет и собственные. Благодаря этому мы можем окружать части кода подобной конструкцией с целью закрыть попавшие внутрь локальные переменные от доступа снаружи. (Один из примеров ее использования вы можете увидеть в исходном коде библиотеки jQuery, которая окружает замыканием весь свой код, чтобы не выводить за его пределы нужные только ей переменные).
Есть, правда, одна связанная с таким применением ловушка — внутри замыкания теряется значение слова this за его пределами. Решается она следующим образом:
(function() { //вышестоящее this сохранится }).call(this);
Рассмотрим еще один прием из той же серии. Повсеместно популяризовали его разработчики фреймворка Yahoo UI, назвав его «Module Pattern» и написав о нем целую статью в официальном блоге.
Пускай у нас есть объект (синглтон), содержащий какие-либо методы и свойства:
С помощью замыкания мы можем сделать методы и свойства, которые вне объекта не используютя, приватными (т.е. доступными только ему):
var MyModule = (function() { var name = 'Habrahabr'; function sayPreved() { alert('PREVED ' + name.toUpperCase()); } return { sayPrevedToHabrahabr: function() { sayPreved(name); } } })(); MyModule.sayPrevedToHabrahabr(); //alerts «PREVED Habrahabr»
Напоследок хочу описать распространенную ошибку, которая многих вгоняет в ступор в случае незнания того, как работают замыкания.
Пускай у нас есть массив ссылок, и наша задача — сделать так, чтобы при клике на каждую выводился алертом ее порядковый номер. Первое решение, что приходит в голову, выглядит так:
for (var i = 0; i < links.length; i++) { links[i].onclick = function() { alert(i); } }
На деле же оказывается, что при клике на любую ссылку выводится одно и то же число — значение links.length. Об этом говорит сайт https://intellect.icu . Почему так происходит? В связи с замыканием объявленная вспомогательная переменная i продолжает существовать, при чем и в тот момент, когда мы кликаем по ссылке. Поскольку к тому времени цикл уже прошел, i остается равным кол-ву ссылок — это значение мы и видим при кликах.
Решается эта проблема следующим образом:
for (var i = 0; i < links.length; i++) { (function(i) { links[i].onclick = function() { alert(i); } })(i); }
Здесь с помощью еще одного замыкания мы «затеняем» переменную i, создавая ее копию в его локальной области видимости на каждом шаге цикла. Благодаря этому все теперь работает как задумывалось.
Замыкание - одно из мощных выразительных средств javascript, которым часто пренебрегают, и даже не советуют употреблять.
Действительно, замыкания могут приводить к проблемам. Но на самом деле они очень удобны, просто нужно понимать, что реально происходит.
Простое описание
Если говорить просто, то замыкание - это внутренняя функция. Ведь javascript разрешает создавать функции по ходу выполнения скрипта. И эти функции имеют доступ к переменным внешней функции.
В этом примере создается внутренняя функция func, изнутри которой доступны как локальные переменные, так и переменные внешней функции outer:
01
functionouter() {
02
varouterVar;
03
04
varfunc = function() {
05
varinnerVar
06
...
07
x = innerVar + outerVar
08
}
09
returnfunc
10
}
Когда заканчивает работать функция outer, внутренняя функция func остается жить, ее можно запускать в другом месте кода.
Получается, что при запуске func используется переменная уже отработавшей функции outer, т.е самим фактом своего существования, funcзамыкает на себя переменные внешней функции (а точнее - всех внешних функций).
Наиболее часто замыкания применяются для назначения функций-обработчиков событий:
1
functionaddHideHandler(sourceId, targetId) {
2
varsourceNode = document.getElementById(sourceId)
3
varhandler = function() {
4
vartargetNode = document.getElementById(targetId)
5
targetNode.style.display = ‘none’
6
}
7
sourceNode.onclick = handler
8
}
Эта функция принимает два ID элементов HTML и ставит первому элементу обработчик onclick, который прячет второй элемент.
Т.е,
// при клике на элемент с ID="clickToHide"
// будет спрятан элемент с ID="info"
addHideHandler("clickToHide", "info")
Здесь динамически созданный обработчик события handler использует targetId из внешней функции для доступа к элементу.
Подробное описание
.. Если Вы хотите углубиться поглубже и разбираться подольше..
..На самом деле происходящее в интерпретаторе Javascript гораздо сложнее и содержит куда больше деталей, чем здесь описано...
..Но чтобы понять и использовать замыкания, достаточно понять внутренний механизм работы функций, хотя бы и в таком, местами упрощенном виде...
[[scope]]
Каждое выполнение функции хранит все переменные в специальном объекте с кодовым именем [[scope]], который нельзя получить в явном виде, но он есть .
Каждый вызов var... - всего лишь создает новое свойство этого объекта, а любое упоминание переменной - первым делом ищется в свойствах этого объекта.
Такова внутренняя структура "области видимости" - это обыкновенный объект. Все изменения локальных переменных являются изменениями свойств этого неявного объекта.
Обычно после того, как функция закончила выполнение, ее область видимости[[scope]], т.е весь набор локальных переменных убивается.
Общий поток выполнения выглядит так:
01
// функция для примера
02
functionsum(x,y) {
03
// неявно создался объект [[scope]]
04
...
05
// в [[scope]] записалось свойство z
06
varz
07
// нашли переменную в [[scope]], [[scope]].z = x+y
08
z = x+y
09
// нашли переменную в [[scope]], return [[scope]].z
10
returnz
11
12
// функция закончилась,
13
// [[scope]] никому больше не нужен и умирает вместе с z
14
}
Кстати, для кода вне функции(и вообще глобальных переменных) роль объекта-контейнера [[scope]] выполняет объект window.
Область видимости вложенной функции
Когда одна функция создается внутри другой, то ей передается ссылка на объект с локальными переменными [[scope]] внешней функции.
Благодаря существованию этой ссылки, из внутренней функции можно получить переменные внешней функции - через ссылку на ее [[scope]]. Сначала ищем у себя, затем - во внешнем [[scope]] - и так далее по цепочке до самого объекта window.
Замыкание - это когда объект локальных переменных [[scope]] внешней функции остается жить после ее завершения.
Внутренняя функция может обратиться к нему в любой момент и получить переменную внешней функции.
Например, разберем работу функции, которая устанавливает обработчики событий:
01
functionaddHideHandler(sourceId, targetId) {
02
// создан объект [[scope]] со свойствами sourceId, targetId
03
04
// записать в [[scope]] свойство sourceNode
05
varsourceNode = document.getElementById(sourceId)
06
07
// записать в [[scope]] свойство handler
08
varhandler = function() {
09
vartargetNode = document.getElementById(targetId)
10
targetNode.style.display = ‘none’
11
}
12
13
sourceNode.onclick = handler
14
15
// функция закончила выполнение
16
// (***) и тут - самое интересное!
17
}
При запуске функции все происходит стандартно:
создается [[scope]]
туда записываются локальные переменные
внутренняя функция получает ссылку на [[scope]]
Но в самом конце - внутренняя функция присваивается sourceNode.onclick. Внешняя функция закончила свою работу, но внутренняя - может запуститься когда-нибудь потом.
Интерпретатор javascript не проводит анализ - понадобятся ли внутренней функции переменные из внешней, и какие переменные могут быть нужны.
Вместо этого он просто оставляет весь [[scope]] внешней функции в живых.
Чтобы когда внутренняя функция запустится, если она вдруг не найдет какую-либо переменную в своем [[scope]] - она могла обратиться к [[scope]] внешней функции и нашла бы ее там.
Если внешняя функция была создана внутри еще одной (еще более внешней) функции - то в цепочку добавляется еще один консервированный [[scope]] и так - до глобальной области window.
Пример на понимание
В этом примере внешняя функция makeShout() создает внутреннюю shout().
01
functionmakeShout() { // (1)
02
varphrase = "Превед!"// (2)
03
04
varshout = function() { // (3,4)
05
alert(phrase)
06
}
07
08
phrase = "Готово!"// (5)
09
10
returnshout
11
}
12
13
shout = makeShout()
14
// что выдаст?
15
shout()
Функция shout() на правах внутренней функции имеет доступ к переменной phrase. Какое значение она выведет - первое или второе?
Если неочевидно - перед тем, как читать дальше, попробуйте этот пример запустить.
А вот - подробное описание происходящего в недрах javascript:
Внутри makeShout()
создается [[scope]]
В [[scope]] пишется: phrase="Превед!"
В [[scope]] пишется: shout=..функция..
При создании функция shout получает ссылку на [[scope]] внешней функции
[[scope]].phrase меняется на новое значение "Готово!"
При запуске shout()
Создается свой собственный объект [[scope2]]
Ищется phrase в [[scope2]] - не найден
Ищется phrase в [[scope]] внешней функции - найдено значение "Готово!"
alert("Готово!")
То есть, внутренняя функция получает последнее значение внешних переменных.
Забавный пример
Замыкание позволяет создать функцию суммирования, которая работает вот так:
1
sum(a)(b) = a+b
2
3
// например
4
sum(1)(3) = 4
Да, именно так: скобки - не опечатки.
А вот и сама функция sum:
1
functionsum(a) {
2
returnfunction(b) {
3
returna+b
4
}
5
}
Пример ошибочного использования
Функция addEvents принимает массив div'ов и ставит каждому вывод своего номера на onclick.
С вопроса "Почему это не работает?" люди обычно начинают изучение замыканий.
1
functionaddEvents(divs) {
2
for(vari=0; i<divs.length; i++) {
3
divs[i].innerHTML = i
4
divs[i].onclick = function() { alert(i) }
5
}
6
}
Для тестового примера сделаем 10 разноцветных нумерованных div'ов с разными цветами:
Кнопка ниже создаст 10 дивов и вызовет для них addEvents
Если Вы покликаете на div'ы - они все выдают одинаковый alert.
Такой глюк возник из-за того, что все функции div[i].onclick получают значение iиз одного на всех [[scope]] внешней функции. А это значение ([[scope]].i) на момент активации onclick-обработчика равно 10 (цикл завершился как толькоi==10).
Чтобы все было в порядке, в таких случаях применяют специальный прием - выделение [[scope]]. Следующая функция работает правильно. В ней все то же самое, кроме div.onclick.
1
functionaddEvents2(divs) {
2
for(vari=0; i<divs.length; i++) {
3
divs[i].innerHTML = i
4
divs[i].onclick = function(x) {
5
returnfunction() { alert(x) }
6
}(i)
7
}
8
}
Теперь все должно быть в порядке - каждый div дает alert на свой номер.
Для присваивания div.onclick запускается временная функция function(x) {..}, принимающая аргумент x и возвращающая обработчик, который берет x из [[scope]]этой временной функции.
Запись function(x) {..} используется для создания функции, и тут же (i) - для запуска с аргументом i.
Вообще, javascript очень удобный в этом смысле язык. Допускает любые конструкции, например, вместо последовательных вызовов:
varf = function(a) { return[0, a, 2*a] }
vart = f(1)
varresult = t[2] // 2
можно в одну строчку создать и тут же вызвать функцию и тут же получить 2й элемент массива:
varresult = function(a){ return[0,a,2*a] }(1)[2]
Временная функция function(x) {..} заканчивает работать тут же, оставляя в своем [[scope]] правильное значение x, равное текущей переменной i цикла.
Когда обработчик активизируется - alert возьмет из [[scope]] ближайшей внешней функциии правильное значение x.
По идее, этих примеров должно хватать для понимания и практического использования замыканий.
Также про замыкания можно почитать, например в cтатьеhttp://www.jibbering.com/faq/faq_notes/closures.html
Конечно, разобрать происходящее во всех деталях позволит стандарт языка ECMA-262.
Объясните Function.prototype.bind.
Когда вы оптимизируете свой код?
Когда бы вы использовали document.write()?
Основы: замыкания, чем отличается .call() от .apply(), на что указывает this, как работает прототипное наследование. Знать ECMAScript 5: например Object.create(), Object.defineProperty(), как работают методы вроде .map(),.filter(), .reduce(). Вероятно, надо знать методы работы с элементами страницы, стандарт DOM3, как работать, чтобы не было тормозов. Как загружается страница, в какой момент исполняются скрипты, как оптимизировать критический путь.AMD и иже с ним. Асинхронное программирование, промисы. (Особенно, если предполагается разработка на node.js.) Паттерны проектирования. Возможно, плюсом будет знание фреймворков вроде Backbone.js, Angular.js или React.js, хотя каждый из них есть за что покритиковать. Профилирование кода. Ну и примеры своего кода: «покажи свой GitHub»
Надеюсь, эта статья про ответы на собеседования frond-end разработчика javascript, была вам полезна, счастья и удачи в ваших начинаниях! Надеюсь, что теперь ты понял что такое ответы на собеседования frond-end разработчика javascript
и для чего все это нужно, а если не понял, или есть замечания,
то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории
Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)
Ответы на вопросы для самопроверки пишите в комментариях,
мы проверим, или же задавайте свой вопрос по данной теме.
Комментарии
Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий,
не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
Комментарии
Оставить комментарий
Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)
Термины: Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)