СоХабр закрыт.

С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.

H Хитрые задачки на собеседовании JavaScript в черновиках Из песочницы

Вы уверены что знаете JavaScript? В таком случае предлагаю вам рассмотреть список моих собственных задач, которые я предлагаю на собеседованиях (на один из проектов крупного банка). Как показала статистика ни один кандидат не смог правильно ответить на все перечисленный вопросы, будь то Junior или Senior. Зато сразу видно кто из кандидатов умеет самостоятельно размышлять, а это довольно ценный навык. Итак, поехали!

1.1. Чему равно g после выполнения следующего кода?

f = g = 0;
(function () {
  try {
    f = function() {
      return f();
    };
    f();
  } catch (e) {
    return g++ && f();
  } finally {
    return ++g;
  }
  function f() { g += 5; return 0; }
}) ();

1.2. Уже начинаете задумываться? Вот еще похожая задачка:

f = g = 0;
(function () {
  try {
    f = function() {
      return f();
    } && f();
  } catch (e) {
    return g++ && f();
  } finally {
    return ++g;
  }
  function f() { g += 5; return 0; }
}) ();

2.1. Эту задачу решить в уме практически невозможно. Вооружитесь бумажкой. Что выведет без 'use strict' и что с 'use strict'?

function b(b) {
  return this.b && b(b)
}

b(b.bind(b))

2.2. Аналогичный вопрос на понимание отличий стрелочных функций.

c = (c) => {
  return this.c && c(c)
}

c(c.bind(c))

3. Немного расслабимся. Самая простая задачка. Как бы не был банален следующий вопрос, однако не все кандидаты с опытом ответили на него правильно, что не перестает меня удивлять и по сей день. Это один из примеров, где знания, казалось бы, ненужного Assembler все-же выручают.

var g = 0;
g = 1 && g++;
console.log(g);

4. Этот вопрос тоже довольно прост. Какие варианты записи правильны и что вернет каждое выражение?

!function(){}()
function(){}()
true && function(){}()
(function(){})()
function(){}
!function(){}

5. Один раз я и сам не смог правильно объяснить что же происходит в этих, придуманных мною, казалось бы двух строчках. Зато каких! Как вы думаете, что вернет выражение?

var a = b = true, c = (a) => a;
(function a(a = c(b).a = c = () => a) { return a(); })()

6. Каков результат самовызывающейся функции?

var a = true;
(a = function () { return a })()

7. Ну и напоследок. Что выведет в консоль?

var v = 0;

try {
  throw v = (function(c) { throw v = function(a){ return v; } })();
} catch (e) {
  console.log (e()());
}

Вы думаете что ответили правильно на все вопросы? Советую убедиться в вашем браузере. Я думаю вы будете приятно удивлены! Если вам будет интересно, пишите в комментариях, и в следующем выпуске мы разберем указанные вами задачи. До встречи!

комментарии (74)

+48
+50 –2
DexterHD ,  
Зато сразу видно кто из кандидатов умеет самостоятельно размышлять, а это довольно ценный навык.

Сразу наталкивает на размышления, какое прикладное значение имеет весь этот код?
Мне кажется ни какого, потому что в продакшене так не пишут. А если пишут надо бить молотком по рукам. IMHO всегда думал что на собеседовании нужно узнать прежде всего будет ли кандидат полезен компании или нет, и сможет ли он решать проблемы бизнеса или нет, а тут проблемами бизнеса и не пахнет. Какой смысл задрачивать идиотские особенности JS и как это задротсво поможет решать проблемы?

Напомнило высказывание автора Homebrew. Хотя оно немного не об этом, но из той же оперы я считаю.
Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.
0
stargazr ,  

А правда ли, что Google уже поменял свою точку зрения?
Вроде бы кто-то оттуда писал, что умение решать олимпиадные задачки не говорит об умении писать промышленный код.

+22
+23 –1
feorex ,  
Абсолютно вредная статья.
–1
+1 –2
babylon ,  

Можно свою задачку для собеседования предложить? Если да, то вот есть массив


var s = [
    ["a", "b"], "&&", ["сидели", "на трубе"], "||", "..."
]

Требуется получить


var r=[{'||':[{"&&:[["a", "b"],["сидели", "на трубе"]]},"..."]}]
+6
+7 –1
f0rk ,  

SyntaxError требуется получить?

–2
staticlab ,  

Старая добрая "сортировочная станция"?

+36
+37 –1
Laney1 ,  
Зато сразу видно кто из кандидатов умеет самостоятельно размышлять

умеющий самостоятельно размышлять кандидат, увидев эти идиотские шарады, сразу встанет и уйдет

+11
+12 –1
A-Stahl ,  
Возможно это и предполагается в качестве правильного ответа:)
0
aamonster ,  

Я бы спросил, что сделают с программистом, который закоммитит такой код. Возможно, ответ бы меня устроил :-)
Интересно, кстати, нанимают ли тех, кто этот вопрос не задал?

+17
+18 –1
f0rk ,  

Задачки забавные, и если бы мне подкинул такие коллега, я бы с удовольствием поразмышлял. Но на собеседовании — нет. Если честно, то возникает ощущение, что цель интервьюирующего — продемонстрировать свое превосходство, а не разобраться, полезен ли кандидат для компании.

+1
rPman ,  
Поставил плюс, в надежде, чтобы статья попала на главную, хочу больше мнений, надеюсь они будут такими же как выше — задачки интересные с академической точки зрения, но как задача на собеседовании может поставить завышенный барьер при выборе работника.
+5
+6 –1
stargazr ,   * (был изменён)

Клоунада какая-то.


Вы думаете что ответили правильно на все вопросы? Советую убедиться в вашем браузере. Я думаю вы будете приятно удивлены!

Если я ошибся, что в этом для меня приятного? А если на все ответил верно, почему я должен быть удивлен выводу браузера? У автора явные проблемы с логикой, отсюда и задачки такие.

+15
+16 –1
ruzhovt ,  
Боже какой ужас. Правильный ответ к любому вопросу — да вы там совсем ё%нулись? встать и уйти
0
+1 –1
AlexZaharow ,  
Вот и вам задачка. Требуется передать на сервер такой объект:
var a = {b:"B"}
a.a=a;

Вам по силам это?
0
f0rk ,  

client:


msg = '() => { var a = {b:"B"}; a.a=a; return a; }';
send(msg);

server:


msg = receive();
res = eval(msg)();
0
staticlab ,  

Ога-ога, эвалить на сервере строку с клиента :)

+4
f0rk ,  

Ога-ога, какой вопрос, такой и ответ. Если сильно хочется, можно свой eval написать, который парсит структуры типа {b:"B",a:"reference(this)"}, вариантов много придумать можно. Но вопрос был "Вам по силам это?", ответ — да, доказательство прилагается :)

–2
AlexZaharow ,  
Да, верно. Отметил в карме. )
0
AlexZaharow ,   * (был изменён)
По-другому никак. JSON не умеет передавать ссылки. Вопрос по сути очень сложный, т.к. нужен был код, который может распарсить внутренние перекрёстные ссылки объекта и сформировать такую колбасу на лету.
Вот другой произвольный объект:
obj = {a:"A", b:{c:"C"}, d:[1,2,3,4,5]};
obj.obj = obj;

Вот результат:
obj={'a':"A",'b':{},'d':{}};
obj['b']={'c':"C"};
obj['d']=[1,2,3,4,5];
obj['obj']=obj;


Или вот закопать объект поглубже:
obj = {a:"A", b:{c:"C"}, d:[1,2,3,4,5]};
obj.d.push(obj);

На выходе:
obj={'a':"A",'b':{},'d':{}};
obj['b']={'c':"C"};
obj['d']=[1,2,3,4,5];
obj['d'][5]=obj;

Да таким «простым» вопросом можно вообще любого кандидата резать. Без ножа.
0
staticlab ,  

Ну если серьёзно, то тут или вспомнить про второй параметр у JSON.stringify, а затем проверять, не встретился ли нам ранее такой объект, и подменить его каким-нибудь фиктивным {$ref: 1}, который затем надо будет корректно восстановить; или написать свой аналог stringify с аналогичной проверкой и дополнительным синтаксисом для ссылок на объекты.

0
AlexZaharow ,  
Вы почти приняты )
+3
iShatokhin ,  

Можно сделать чуть безопасней (запретить доступ к локальной области видимости).


msg = receive();
res = new Function('msg', `return ${msg}`)();
0
iShatokhin ,  

Опечатался, аргумент 'msg' там не нужен...

0
AlexZaharow ,  
Интересно. Эту тонкость никогда не имел в виду! Буду знать. Спасибо.
0
iShatokhin ,  

Клиентская часть


var isObject = function (obj) {
  return Object.prototype.toString.call(obj) === "[object Object]";
};

var map = new Map();
var paths = [];

function three (tr) {
    function findPath(branch, path) {
        path = path.concat();

        if (path.length && map.has(branch)) {
            paths.push([path.concat(), map.get(branch).concat()]);
        } else {
            map.set(branch, path.concat());

            Object.keys(branch).forEach(function (key) {
                var val = branch[key];

                if (Array.isArray(val) || isObject(val)) {
                    findPath(val, path.concat([key]));
                } else {
                    paths.push([path.concat([key]), val]);
                }
            });
        }
    }

    findPath(tr, []);

    return paths;
}

var obj = {a:"A", b:{c:"C"}, d:[1,2,3,4,5]};
obj.obj = obj;

var msg = JSON.stringify(three(obj));

send(msg);

Серверная часть


var _ = require('lodash');

var msg = receive();

var obj = {};

JSON.parse(msg).forEach(function ([path, val]) {
    if (Array.isArray(val)) {
        if (val.length === 0) {
            _.set(obj, path, new_a);
        } else {
            _.set(obj, path, _.get(obj, val));
        }
    } else {
        _.set(obj, path, val);
    }
});

Без всяких eval, но с lodash (при желании, можно написать самому методы set/get).

0
iShatokhin ,   * (был изменён)

Небольшая опечатка — new_a надо заменить на obj.


Результат можно проверить в консоли — https://jsfiddle.net/m5p2vz09/

+2
ChALkeRx ,  

Бесполезно это, потому что и из глобальной и в ноде и в браузере много чего можно наворотить.
Не надо евалить всё. Смотрите, как тот же cycle делает, хотя бы (хотя имхо это тоже так себе подход).

0
iShatokhin ,  

А если так?


const msg = receive(); // `a = {b:"B"}; a.a=a;`

const sandbox = {
    a: null,
    require: null // так же можно запретить доступ к модулям на всякий случай?
};

const script = new vm.Script(msg),
    context = new vm.createContext(sandbox);

script.runInContext(context);

console.log(sandbox.a);
+2
ChALkeRx ,  

И снова нет.


Пример: msg = "while(true){}", и всё, ваш сервер повис.


vm — не способ запуска недоверенного кода.

0
wheercool ,  
А где в условии сказано что сервер на js? :)
0
AlexZaharow ,  
Сервер не обязательно на JS. Можно и Java/Nashorn.
0
iShatokhin ,  

Так это ничего не поменяет, все тот же eval.


ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
engine.eval(msg);
Object obj = engine.get("a");

p.s. несколько лет не писал на JAVA, могу и ошибиться

0
aamonster ,  

Сам не яваскриптер, но полюбопытствовал в гугле — оказывается, есть как более-менее распространённые реализации в либах (типа dojo), так и довольно простой подход через второй аргумент JSON.stringify.
eval — стрёмно :-).
А в реальной жизни я бы постарался преобразовать граф в дерево.

0
ChALkeRx ,   * (был изменён)

https://www.npmjs.com/package/cycle же, ну.
Но если вам приходится кидаться такими объектами, то у вас в структуре, наверное, что-то не то.

0
AlexZaharow ,  
К счастью не пришлось. Передачу на сервер замутил чисто из академических интересов. Но обход структуры и поиск зацикливаний был. Среди прочего надо было получать список объектов для вотчеров коллекций ангуляра.
0
ChALkeRx ,  
Но обход структуры и поиск зацикливаний был.

Это уже чуть другая задачка, заметно более простая.
См. https://github.com/davidmarkclements/fast-safe-stringify/blob/master/index.js, например.

0
AlexZaharow ,   * (был изменён)
Норм. Но лично я упирался и хотел сохранить структуру объекта. А так куски кода до боли знакомы. ) Спасибо за ссылку.
0
bano-notit ,  

Сделать конечно можно идиотским способом, но вопрос другой: зачем? Вот никогда не видел, чтобы такие циклические ссылки использовались где-то в проде. Может приведёте примерчик, где такие интереснейшие утечки люди используют?

0
wheercool ,  
Любые графовые задачи. В общем случае граф может содержать циклы. Самый простой пример — моделирование карты.
Да, я в курсе, что можно использовать матрицу смежности, но не для всех типов алгоритмов она применима.
Кстати, матрица смежности, вроде как может решить проблему циклических ссылок, правда не эффективно )
+1
vintage ,  

Есть и другие способы хранить граф. Например в виде словаря узлов и словаря связей.

+1
Antelle ,   * (был изменён)

Мне страшно представить, каких людей вы набираете, предлагая такие задачки, какой код получаете в результате и для какой цели подобные вопросы задавать (у вас много такого кода?). Решается раз и навсегда запретом на такие штуки в линтере.

–1
staticlab ,  

Имхо даже линтер с минимальным набором правил просто пошлёт такой код куда подальше.

+4
+6 –2
webinside ,  
image
+1
+2 –1
AlexZaharow ,  
У моей жены есть подруга, которая хотела выйти замуж за умного. И одним из первых вопросов у неё было «А сколько у вас научных работ?». В итоге замуж вышла. За военного.
0
+1 –1
dom1n1k ,  
Мозгоклюйство какое-то
+4
+5 –1
pinebit ,  
Читаю такое и всякий раз радуюсь тому, что не работаю на «крупный банк». Хотя я знаю больше половины ответов, пишу себе спокойно примитивные конструкции на JavaScript, и зарабатываю больше, чем такие с позволения сказать «эрудиты». Коллеги хвалят за простой понятный код, заказчик исправно платит $, но да — нет в моем резюме всяких Сбертехов (точнее — есть, но больше не надо).
В последнее время я все больше разделяю политику интервью крупных IT компаний, которые просят развернуть список на доске/бумажке. В большинстве солидных компаний в которых мне довелось работать — почти везде были запрещены подобные задачи.
Так что да — встать и уйти, и не забыть написать отзыв.
0
urrri ,  
Если рассматривать это как quiz, то задачки очень интересные. В основном только пост-фактум удается понять почему именно такой результат. Я, например, так и не понял в “ассемблерной” задачке, почему получается 0.

Если давать такое на интервью, то это большая ошибка. Любой человек нервничает на интервью, и даже понимая язык, вряд ли решит задачу правильно, даже более легкую. Да и вообще это не имеет смысла. Для проверки понимания языка не нужны такие навороты. Нужна проверка знаний основных нюансов языка, например всплытие функций или область видимости var. Это достигается более простыми задачками, но даже это не отражает способность человека думать.
0
+1 –1
vintage ,  

Сначала идёт постинкремент, а потом присваивание, очевидно. Но вот при чём тут ассемблер?

+13
Landgraph ,  
Автор, я так понимаю, ищет на работу интерпретатор JS?

Не могли бы Вы к каждому пункту указать, что именно Вы таким образом проверяете?
0
+1 –1
MikailBag ,  

Работу встроенного в мозг экземпляра v8, наверно.

0
+1 –1
ZoomLS ,  
Вы, наверное, ещё задаёте вопросы в духе — почему у колодцев крышки круглые и т.п.?
0
vintage ,  
typeof document.createElement( 'object' )

Что вернёт и почему?

+1
ChALkeRx ,  

Ога.


  • Array(40).fill(NaN).map(parseInt)
    Array(40).fill(null).map(parseInt)
    Array(40).fill(false).map(parseInt)

  • ({'':42})[[[]]]
    [1,2,3][[[1]]]

  • > {} + []
    0
    > [] + {}
    '[object Object]'
    > typeof ([] + {})
    'string'
    > typeof ({} + [])
    'string'
    > {} + [] == [] + {}
    true
    > {} + [] == {} + []
    false


И много других занимательных вещей смотрите в нашем КВН =).


У всех вышеперечисленных, кстати, простые объяснения, и они все гораздо менее упороты, чем задачки из собеседований на один из проектов крупного банка. Но на собеседовании я бы их задавать всё равно не стал.

+1
SamSol ,  
Очень хорошие примеры! Только вопрос должен быть другой: «Какие из этих фрагментов кода ты бы забраковал на код ревью»?
+1
ChALkeRx ,   * (был изменён)

Но тогда стоило бы разбавить нормальными, потому что сейчас правильный ответ — «все».


Хотя вообще-то это даже до код ревью дойти не должно, линт такую ерунду на CI должен срезать.

0
staticlab ,  

Линт такую ерунду уже при коммите должен срезать, если только раньше IDE с линтером хором материться не начали.

+1
ChALkeRx ,  
Линт такую ерунду уже при коммите должен срезать, если только раньше IDE с линтером хором материться не начали.

Это уже зависит от настроек на компьютере конкретного разработчика, каждый программирует, в чём хочет. В большинстве случаев — да, ещё до коммита. Но на CI это должно срезаться однозначно.

0
vintage ,  

Кстати, я на собеседовании не задаю задачек вообще — по беседе и так быстро становится понятно насколько глубоко человек знаком с предметом. И, кстати, мы ищем фронтендеров в Питере — стучитесь в личку за подробностями :-)

+2
jbubsk ,  
Вы предлагаете это на один из проектов крупного банка? С вашим банком что-то не так.
0
staticlab ,  

Работать в нём — большая честь!

0
Pakos ,  
Это защита от исследователя скриптов — большинство сходит с ума и хохоча убегает в закат. К сожалению, не факт что в будущем так не сделает тот же интерпретатор JS и заберёт с собой в закат и работоспособный сайт.
0
justboris ,  

Это как раз вряд ли. Все эти грабли хоть и странные, но описаны в стандарте, которому следуют все интерпретаторы. А зная, что нововведения в JS обычно делаются с обратной совместимостью, скорее всего ничего не сломается.

0
Aries_ua ,  
Хочу добавить — никто не девелопит в стрессовой ситуации. А если она возникает, то стараются успокоится и расслабится, что бы лучше понимать, что надо делать.

Когда то на одном собеседовании предложили попрограмить на бумажке. Ну а что, тыжпрограммист! Конечно программить не стал и сказал им, что ребята — вы просто потратили мое время, а ваши тесты глупы. Начитались наверное у гугла, как собеседовать. Удачи вам.

Теперь к задачкам в статье — скажите, как они мне помогут определить, сможет ли человек найти общий язык со всеми в команде? Сможет ли человек разработать солюшен для какого ни буть компонента или модуля? Имеет ли человек какие нибудь наработки, к примеру во фронтенде? Делал ли человек что-то на других языках, кроме JS?

Могу еще накидать 10-к вопросов, которые я задаю на техническом собеседовании. Но не в них суть.

Дело в том, что ни один из вопросов статьи не ответит на мои поставленные вопросы.

Выше к комментариях верное замечание — «вредные советы».
0
jodaka ,  
Я Вам завидую, потому что фраза «никто не девелопит в стрессовой ситуации», мягко говоря, не для всех работает. Стрессовых ситуаций в моей практике встречается довольно много, и умение вести себя в них адекватно ничуть не менее важно, чем любой другой навык.

За последние несколько лет я побывал, наверное, на дюжине технических интервью. На половине из них были подобные вопросы. При этом, если Вас интервьюируют адекватные люди, то они сразу предупреждают, что цель вопросов — понять, насколько хорошо я знаю замыкания, асинхронную природу js, различные синтаксические конструкции и т.п. Т.е. вполне очевидно, что никто не собирается подобный код в продакшене использовать.

Интервью в компанию, в которой я сейчас работаю, включало подобные каверзные вопросы. А, когда я упомянул, что у меня был опыт разработки под андроид на Java, то мне предложили ещё и инвертировать односвязный список. Опять-же, всем было понятно, что никаких односвязных списков я в своей практике фронтэндера разворачивать не буду, но компания посчитала нужным оценить и эти знания.

Опять-же, мой опыт подсказывает, что подобные вопросы обычно составляют лишь часть технического интервью (как правило, незначительную). А вот в остальное время говорят как раз про опыт разработки, какие-то личные профессиональные интересы и т.п.
0
Aries_ua ,  
По поводу стрессовой ситуации.

Когда они возникают, я стараюсь успокоить команду, расслабить. Хорошо идет к примеру покупка пиццы и 10-15 минутный перерыв с поеданием пиццы и выпиванием кофе с отвлеченными разговорами. Люди переключаются, отвлекаются от проблемы, а когда к ней возвращаются — то уже более трезво ее оценивают или находят другие пути решения.

Если у вас возникают постоянно стрессовые ситуации, значит вы что-то делаете не так.
+1
northicewind ,  
Это издевательство над кандидатами(если это не кандидат в модераторы govnokod.ru). Вместо того, чтоб узнать как у человека с алгоритмическим мышлением, опытом в решении прикладных задач и возможностью поиска решения возникающих проблем, вы кидаете ему в голову это…
0
+1 –1
bano-notit ,  

Вот мне интересно. И много у Вас людей ответило на все эти задачки? Мне кажется, что нет. А ещё мне интересно, Вы сами использовали это в реальной работе?
Вот лично я такие неявности не использовал, да и вообще, использовать неявные конструкции языка — мовитон. Ибо за такой код и руки могут оторвать, потому что он работает совершенно не так, как видится.
Прикольно будет, когда у Вас в проекте будет баг из-за такой вот вещи, потому что кандидат подумал, что такие конструкции неплохо бы использовать в реальной жизни.

–1
bioroot ,  
Вспоминается олдскульная шутка — писать на Perl можно на любом языке. А из задач с подковыркой моя любимая:
if (a != a) {
  alert(a);
}

Вопрос: существует ли такое a, при котором мы увидим алерт? Как ни странно, даже опытные js-программисты не всегда могут ответить на этот вопрос.
+1
dshster ,  
NaN же
+4
vintage ,  

Опытные jquery-программисты, выхотели сказать?

0
bioroot ,  
Если бы. В jQuery про это с давних времён написано в мануале: NaN_and_Infinity. Технология тут не при чём. Просто многие изучают язык (любой) сразу садясь за высокоуровневый фреймворк и в лучшем случае читают про фундамент языка по диагонали.
+5
vintage ,  

Ёсли бы jquery-программисты читалимануалы… их бы называли js-программистами :-)

–1
tarasikgoga ,  
var a = b = true, c = (a) => a;
(function a(a = c(b).a = c = () => a) { return a(); })()

Используете стеролчные ф-ции но при этом объявляете переменные с помощью var?
+1
Aingis ,  

«Объявляете» — это громко сказано. Переменная b так вообще не объявлена. И этим страдают многие примеры.