habrahabr

JavaScript. Вопросы на собеседовании

  • воскресенье, 5 октября 2014 г. в 03:10:50
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 годных интересных вопросов по теме