Вопросы по JavaScript
Ответы на Вопросы кандидату на должность фронтенд-разработчика - Вопросы по Javascript.
- Объясните делегирование событий
- Объясните, как
thisработает в JavaScript - Расскажите, как работает прототипное наследование
- Что вы думаете о AMD против CommonJS?
- Объясните, почему это не является IIFE:
function foo(){ }();. Что необходимо изменить, чтобы это стало IIFE?? - В чем различие между переменными, значение которых:
null,undefinedи не объявлено? Как бы вы проверили их на каждое из этих значений? - Что такое замыкание и как/для чего его используют?
- Можете ли вы описать основное различие между циклом
.forEachи циклом.map()? И в каких случаях каждый из них используется? - В каких случаях обычно используются анонимные функции?
- Как вы организуете свой код? (module pattern, classical inheritance)
- В чем разница между host-объектами и нативными объектами?
- В чем разница между:
function Person(){},var person = Person(), иvar person = new Person()? - В чем разница между
.callи.apply? - Что делает и для чего нужна функция
Function.prototype.bind? - В каких случаях используется
document.write()? - В чем разница между feature detection (определение возможностей браузера), feature inference (предположение возможностей) и анализом строки user-agent?
- Расскажите об Ajax как можно более подробно
- Какие преимущества и недостатки в использовании Ajax?
- Объясните, как работает JSONP (и почему это не совсем AJAX)
- Вы когда-нибудь использовали шаблонизацию на JavaScript? Если да, то какие библиотеки вы использовали?
- Расскажите, что такое поднятие (hoisting)
- Объясните, что такое всплытие событий (event bubbling)
- В чем разница между "атрибутом" (attribute) и "свойством" (property)?
- Почему не следует расширять нативные JavaScript-объекты?
- В чем разница между событием
loadи событиемDOMContentLoaded? - В чем разница между
==и===? - Объясните same-origin policy в контексте JavaScript
- Сделайте так, чтобы этот код работал:
- Почему тернарный оператор так называется?
- Что делает строчка "use strict";? Какие достоинства и недостатки от ее использования?
- Напишите цикл, который перебирает числа до
100, возвращая "fizz" на числа кратные3, "buzz" на числа кратные5и "fizzbuzz" на числа кратные3и5. - Почему считается хорошим тоном оставить глобальную область видимости (global scope) в нетронутом состоянии?
- Для чего используют событие
load? Есть ли у этого события недостатки? Знаете ли вы какие-либо альтернативы, и в каких случаях бы стали их использовать? - Расскажите, что такое одностраничное приложение, и как сделать его SEO-оптимизированным.
- Насколько вы опытны в работе с промисами (promises) и/или их полифилами?
- Какие преимущества и недостатки при использовании промисов вместо колбэков (callbacks)?
- Каковы преимущества и недостатки написания JavaScript-кода на языке, который компилируется в JavaScript?
- Какие инструменты и методы вы используете при отладке кода?
- Какие языковые конструкции вы используете для итерации по свойствам объекта и элементам массива?
- Объясните разницу между изменяемыми (mutable) и неизменяемыми (immutable) об ъектами
- Объясните разницу между синхронными и асинхронными функциями
- Что такое цикл событий (event loop)? В чем разница между стеком вызовов (call stack) и очередью событий (task queue)?
- Объясните разницу при использовании
fooвfunction foo() {}иvar foo = function() {} - В чем различие между переменными, созданными при помощи
let,varиconst? - В чем разница между классом в ES6 и функцией-конструктором в ES5?
- Можете ли вы привести пример использования стрелочных функции =>? Чем они отличаются от других функций?
- В чем преимущество использования стрелочных функций для метода в конструкторе?
- Дайте определение функции высшего порядка
- Можете ли вы привести пример деструктуризации объекта или массива?
- Шаблонные строки в ES6 намного упрощают создание строк, можете ли вы привести пример их использования?
- Можете ли вы привести пример каррированной функции (curry function) и в чем их преимущество?
- В чем преимущества использования spread оператора и чем он отличается от rest оператора?
- Каким образом можно обмениваться кодом между файлами?
- Для чего используются стат ические члены класса?
- Другие ответы
Объясните делегирование событий
Делегирование событий - это приём, заключающийся в добавлении обработчиков событий к родительскому элементу, а не к дочерним элементам. Обработчик будет срабатывать всякий раз, когда событие будет запущено на дочерних элементах благодаря всплытию событий в DOM. Преимущества этого приёма:
- Экономит объем используемой памяти, т.к. для родительского элемента требуется только один обработчик.
- Не нужно привязывать или убирать обработчики при добавлении и удалении элементов.
Ссылки
- https://davidwalsh.name/event-delegate
- https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation
Объясните, как this работает в JavaScript
Нельзя в двух словах объяснить работу ключевого слова this; это одно из самых запутанных понятий в JavaScript. Говоря максимально простым языком, значение this зависит от того, как вызывается функция. Я прочитал много объяснений о работе this, и считаю объяснение Arnav Aggrawal наиболее понятным. Применяются следующие правила:
- Если ключевое слово
newиспользуется при вызове функции,thisвнутри функции является совершенно новым объектом. - Если для вызова/создания функции используются
apply,callилиbind, тоthisвнутри функции - это объект, который передается в качестве аргумента. - Если функция вызывается как метод, например,
obj.method(), тоthis- это объект, к которому принадлежит функ ция. - Если функция вызывается без контекста, то есть она вызывается без условий, описанных в пунктах выше, то
thisявляется глобальным объектом. В браузере это объектwindow. В строгом режиме ('use strict'),thisбудетundefinedвместо глобального объекта. - Если применяются несколько из вышеперечисленных правил, то правило, которое выше выигрывает и устанавливает значение
this. - Если функция является стрелочной функцией, то она игнорирует все вышеописанные правила и получает значение
thisиз лексического окружения во время ее создания.
Чтобы получить более подробное объяснение, ознакомьтесь с его статьей на Medium.
Ссылки
- https://codeburst.io/the-simple-rules-to-this-in-javascript-35d97f31bde3
- https://stackoverflow.com/a/3127440/1751946
Расскажите, как работает прототипное наследование
Этот вопрос очень часто задают на собеседованиях. Все объекты в JavaScript имеют свойство __proto__, которое является ссылкой на другой объект. Когда происходит обращение к свойству объекта, и если свойство не найдено в этом объекте, то механизм JavaScript просматривает прототип объекта, затем прототип прототипа и т.д. До тех пор, пока не найдет определенное свойство на одном из прототипов или до тех пор, пока он не достигнет конца цепочки прототипов. Такое поведение имитирует классическое наследование, но на самом деле это скорее делегирование, чем наследование.
Ссылки
- https://www.quora.com/What-is-prototypal-inheritance/answer/Kyle-Simpson
- https://davidwalsh.name/javascript-objects
Что вы думаете о AMD против CommonJS?
Оба являются способами реализации системы модулей, которая изначально не присутствовала в JavaScript до появления ES2015. CommonJS является синхронным, в то время как AMD (Asynchronous Module Definition, асинхронное определение модуля) - соответственно, асинхронным. CommonJS разработан с учетом разработки на стороне сервера, в то время как AMD с поддержкой асинхронной загрузки модулей больше предназначена для браузеров.
Я считаю синтаксис AMD довольно многословным, а CommonJS ближе к стилю, который используется в выражениях импорта в других языках. В большинстве случаев я считаю AMD ненужным, потому что если вы разместите весь свой код в одном объединенном файле, то вы не сможете воспользоваться свойствами асинхронной загрузки. Кроме того, синтаксис CommonJS ближе к стилю написания модулей Node, и поэтому происходит меньше путаницы при переключении между клиентской и серверной разработкой на JavaScript.
Я рад, что с появлением модулей ES2015, которые поддерживают как синхронную, так и асинхронную загрузку, мы, наконец, можем придерживаться одного подхода. Несмотря на то, что они не полностью поддерживаются во всех браузерах и Node, мы можем использовать транспайлеры для преобразования нашего кода.
Ссылки
- https://auth0.com/blog/javascript-module-systems-showdown/
- https://stackoverflow.com/questions/16521471/relation-between-commonjs-amd-and-requirejs
Объясните, почему это не является IIFE: function foo(){ }();. Что необходимо изменить, чтобы это стало IIFE??
IIFE расшифровывается как Immediately Invoked Function Expression - немедленно вызываемое функциональное выражение. Синтаксический анализатор JavaScript читает function foo(){ } (); как function foo(){ } и ();, где первое выражение - это объявление функции, а второе (пара скобок) - попытка вызова функции, но так как имя не указано, он выдает ошибку Uncaught SyntaxError: Unexpected token.
Вот два способа исправить это, которые заключаются добавление дополнительных скобок: (function foo(){ })() и (function foo(){ }()). Выражения, начинающиеся с function, считаются объявлениями функций. Оборачивая эту функцию внутри (), она становится функциональным выражением, которое затем может быть выполнено с последующим (). Подобные функции не отображаются в глобальной области видимости, и вы можете даже не указывать им имя, если вы не будете на них ссылаться.
Вы также можете использовать оператор void - void function foo(){ }(). К сожалению, с таким подходом есть одна проблема. Выполнение данного выражения всегда возвращает undefined, поэтому, если ваше IIFE возвращает что-либо, вы не можете его использовать. Пример:
const foo = void (function bar() {
return 'foo';
})();
console.log(foo); // undefined
Ссылки
- http://lucybain.com/blog/2014/immediately-invoked-function-expression/
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
В чем различие между переменными, значение которых: null, undefined и не объявлено? Как бы вы проверили их на каждое из этих значений?
Необъявленные переменные создаются, когда вы присваиваете значение идентификатору, который не был ранее создан при помощи var,let или const. Необъявленные переменные будут определены глобально, вне текущей области видимости. В строгом режиме, будет ошибка ReferenceError, когда вы попытаетесь назначить значение необъявленной переменной. Необъявленные переменные плохи так же, как и глобальные переменные. Избегайте их любой ценой! Чтобы проверить на их наличие, оберните код в блок try/catch.
function foo() {
x = 1; // ReferenceError в строгом режиме
}
foo();
console.log(x); // 1
Переменная undefined - это переменная, которая была объявлена, но ей не было присвоено зн ачение. Ее тип undefined. Если переменной присвоить функцию, которая не возвращает никакого значения, то переменная также будет иметь значение undefined. Чтобы проверить это, сравните, используя оператор строгого равенства (===) или typeof, который вернет строку 'undefined'. Обратите внимание, что вам не следует использовать оператор абстрактного сравнения для проверки, так как он также вернет true, если значение равно null.
var foo;
console.log(foo); // undefined
console.log(foo === undefined); // true
console.log(typeof foo === 'undefined'); // true
console.log(foo == null); // true. Неправильно, не используйте это для проверки!
function bar() {}
var baz = bar();
console.log(baz); // undefined
Переменной со значением null было явно присвоено значение null. Она отличается от undefined тем, что она была назначена явно. Чтобы проверить на null, просто сравните, используя оператор строгого равенства. Обратите внимание, что, как и выше, вы не должны использовать оператор абстрактного равенства (==) для проверки, так как он также вернет true, если значение равно undefined.
var foo = null;
console.log(foo === null); // true
console.log(typeof foo === 'object'); // true
console.log(foo == undefined); // true. Неправильно, не используйте это для проверки!
Личная привычка - я никогда не оставляю свои переменные необъявленными или неприсвоенными. Я явно назначаю им null после объявления, если я не собираюсь их пока использовать. Если вы используете линтер в своем рабочем процессе, он обычно также проверяет, что вы не ссылаетесь на необъявленные переменные.
Ссылки
- https://stackoverflow.com/questions/15985875/effect-of-declared-and-undeclared-variables
- https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/undefined
Что такое замыкание и как/для чего его используют?
Замыкание - это комбинация функции и лексического окружения, в которой эта функция была объявлена. Слово "лексический" относится к тому факту, что лексическая область видимости использует место, где переменная объявлена в исходном коде, чтобы определить, где эта переменная доступна. Замыкания - это функции, которые имеют доступ к переменным внешней (замыкающей) функции - цепочке областей видимости даже после того, как внешняя функция вернулась.
Для чего его используют?
- Конфиденциальность данных / эмуляция скрытых методов при помощи замыканий. Обычно используется в модульном паттерне.
- Частичное применение функций или каррирование.
Ссылки
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
- https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36
Можете ли вы описать основное различие между циклом .forEach и циклом .map()? И в каких случаях каждый из них используется?
Чтобы понять разницу между ними, давайте посмотрим, что делает каждая функция.
forEach
- Перебирает элементы в массиве.
- Вызывает callback-функцию для каждого элемента.
- Не возвращает значение.
const a = [1, 2, 3];
const doubled = a.forEach((num, index) => {
// Делаем что-либо с num и/или index.
});
// doubled = undefined
map
- Перебирает элементы в массиве.
- "Сопоставляет" каждый элемент с новым элементом, вызывая функцию для каждого элемента, создавая в результате новый массив.
const a = [1, 2, 3];
const doubled = a.map((num) => {
return num * 2;
});
// doubled = [2, 4, 6]
Основное различие между .forEach и .map() состоит в том, что .map() возвращает новый массив. Если вам нужен результат, но вы не хотите изменять исходный массив, .map() - очевидный выбор. Если вам просто нужно перебрать массив, то стоит воспользоваться forEach.