5 вопросов по JavaScript на которые вы должны знать ответ
На собеседованиях часто любят задавать однотипные вопросы, ответы на которые уже давно выучены.
Сегодня же мы рассмотрим те вопросы, про которые вспоминают достаточно редко.
И так, начнём!
1. Чему равно foo.x ?
var foo = {n: 1};
var bar = foo;
foo.x = foo = {n: 2};
Этот вопрос задают в топ 3% компаний (Apple, Google, Facebook).
Главное на что здесь стоит обратить внимание, так это то, что foo
на которую ссылается foo.x
“устанавливается” перед тем как foo
изменится. foo.x
ссылается на старое значение foo.
See section 11.13.1 of the ES5 spec:
- Let lref be the result of evaluating LeftHandSideExpression.
- Let rref be the result of evaluating AssignmentExpression.
Это значит, что в старом foo
появиться новое свойство x
равное {n: 2}
. А в новое foo
запишется {n: 2}
.
Значение старого foo
находиться в bar
:
// bar
{
n: 1,
x: {
n: 2
}
}
Так как при дальнейшем выводе foo.x
наше foo
ссылается на его новое значение, в котором отсутствует x
, то соответственно foo.x
будет не определенно — undefined
.
Ответ: undefined
2. Напишите функцию сложения вида add(num1)(num2)..
Примечание: Количество слагаемых не ограничено
В оригинале это задача решается таким образом:
const add = (a) => { let sum = a; const func = (b) => { if (b) { sum += b; return func; } else { return sum; } }; return func; };add(2)(3)(); // 5;
Но потом вам ставят одно условие.
Убрать в конце лишние скобки
add(2)(3) // 5add(1)(2)(5) // 8...
Теперь задача усложнилась. А решение кроется в переопределении метода valueOf .
Ответ:
const add = (a) => { let sum = a; const func = (b) => { sum += b; return func; }; func.valueOf = () => sum;return func; };console.log(add(2)(3)); // 5;
Когда мы вызываем console.log , он ожидает увидеть String, если его там нет, то он попытается сделать из полученного значения String.
В примере выше после выполнения add(2)(3)
возвращается function, которую console.log будет превращать в String, в ходе этих действий будет вызван метод valueOf для преобразования function к примитиву, а так мы переопределили данный метод, то он вернёт наше значение sum вместо стандартного.
Подробнее об этом тут.
Примечание:
Данный пример не работает со всеми console.
3. Что выведется в консоль ? Объясните почему.
var a={},
b={key:'b'},
c={key:'c'};
a[b]=123;
a[c]=456;
console.log(a[b]);
Ответ: 456
Что же происходит? Когда у объекта устанавливается новое свойство, то JavaScript неявно сделает stringify значения. В коде выше b
и c
являются объектами, следовательно они оба конвертируются в "[object Object]"
(String). Так как stringify значения равны, то получается, что мы присваиваем новое значение одному и тому же свойству.
Равносильно, что написать:
var a={},
b='object',
c='object';
a[b]=123;
a[c]=456;
4. Напишите простую функцию, чтобы узнать равен ли один из входных параметров 3.
Тут делается упор на проверку знаний об arguments
, но иногда заходят ещё дальше и просят рассказать каким образом работает Array.prototype.slice.call(arguments).
Ответ:
function isThreePassed(){ const args = Array.prototype.slice.call(arguments); return args.indexOf(3) != -1; }isThreePassed(1,2) //false isThreePassed(9,3,4,9) //true
Как мы знаем, arguments не массив, а обычный объект, поэтому у него нет такого полезного метода как indexOf. Для этого используется Array.prototype.slice.call(arguments), который делает из argument — > array.
Но всё же, как он работает ?
.call() и .apply() позволяют явно установить this в функции. И если передать argument как this, то slice будет работать с ним как с обычным массивом.
А вот интересный эксперимент:
const o = { '0': 'zero', '1': 'one' };[].slice.call(o); // [];const oo = { '0': 'zero', '1': 'one', length: 2 };[].slice.call(oo); // ["zero", "one"];
5. Объедините два массива с вложенностью
[1, [1, 2, [3, 4]], [2, 4]] -> [1, 1, 2, 3, 4, 2, 4]
Задачу можно решать различными способами. Обычно хотят узнать знает ли собеседуемый такой метод как reduce.
Идея заключается в том, чтобы обойти все элементы исходного массива и его “под массивов” с целью вернуть найденные значения в новый массив. Это происходит рекурсивно пока мы не дойдём до последнего элемента.
Так же с формированием нового массива нам помогает concat.
Ответ:
const flatten = (arr) => arr.reduce((flat, toFlatten) => flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten), []);