http://habrahabr.ru/post/239065/
Не так давно озадачился поиском работы, в связи с чем посетил n-нное количество собеседований и услышал много интересных вопросов. По сети гуляет много статей с вопросами по JS, поэтому постараюсь выбрать вопросы, которые ещё не видел. Здесь нет вопросов типа
Что такое замыкание?,
Наследование в JavaScript или
Сделайте ajax запрос на VanillaJS. Кстати советую поискать ответы на эти вопросы, прежде чем читать статью :) Под катом вопросы типа «с подвохом». Вряд ли какой-то из них попадётся вам, но, надеюсь, статья настроит вас на «подвоховое» мышление, и напомнит некоторые скользкие места и подводные камушки javascript.
Hoisting
Hoisting — всплытие переменных объявленных в функции.
Здесь можно подробно узнать о том как это бывает.
А вот интересный вопрос:
(function() {
f();
f = function() {
console.log(1);
}
})()
function f() {
console.log(2)
}
f();
Что мы увидим в консоли?
ОтветОбъявленная в gs
function f()
всплывёт, соответственно при вызове
f
внутри анонимной функции мы увидим не
ReferenceError
, как кто-то мог предположить, а двойку в консоли, при повторном вызове переменная f уже ссылается на функцию которая печатает 1.
Результат:
< (function() {
f();
f = function() {
console.log(1);
}
})()
function f() {
console.log(2)
}
f();
> undefined
2
1
Если вы сходу уловили подвох предыдущей задачи — не обольщайтесь. Вот ещё интересный пример кода:
(function() {
var x = 1;
function x() {};
console.log(x);
})()
Что теперь мы увидим в консоли?
ОтветФункции объявленный при помощи function declaration имеют больший приоритет и понимаются выше var
. Поэтому интерпретатор сначала выполнит function x() {};
, а затем var x = 1
;
< (function() {
var x = 1;
function x() {};
console.log(x);
})()
> undefined
1
Ну и напоследок. Напомню советы Дугласа Крокфорда: избегать слабых сторон языка и использовать сильные и использовать JSLint.
Чтобы не наткнуться на такие сюрпризы можно взять за привычку самому выносить var в начало функции и объявлять функцию через function expression
Передача по ссылке
Наверное все знают что все объекты передаются в javascript по ссылке:
var obj = {
a: 1
};
(function(obj) {
obj = {
a: 2
};
})(obj);
console.log(obj.a);
Не знаю как вы, а я засыпался на этом вопросе. Я точно знал что объект не измениться после вызова функции, но объяснить почему так и не смог.
А вот почему!При вызове анонимной функции создастся локальная переменная obj в её области видимости. А затем создаётся новый объект {a : 2}
, ссылка на который попадает в локальную переменную obj, но переменная из верхнего скоупа будет всё так же ссылаться на старый объект.
Контекст выполнения
Контекст выполнения функции — мощный и выразительный механизм, если умело его использовать. Правда есть несколько моментов о которых не стоит забывать. Простой пример. Рассмотрим класс который логгирует некие действия.
Logger = function(logFn) {
_logFn = logFn;
this.log = function(message) {
_logFn(new Date() + ": " + message);
}
}
var logger = new Logger(console.log);
logger.log("Hi!");
logger.log("Wazzup?");
Что будет в консоли? Как починить?
ОтветВ консоли мы увидим
TypeError: Illegal invocation
А всё потому что при вызове
logger.log()
, контекст выполнения функции —
logger
Чтобы починить можно вспомнить про встроенные методы функций
.apply()
,
.call()
,
.bind()
< rightLogger = new Logger(console.log.bind(console))
> Logger {log: function}
< rightLogger.log("It's works")
> Sat Oct 04 2014 00:32:49 GMT+0400 (MSK): It's works
UPD: ещё набор из 5 годных интересных вопросов по теме