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)
babylon
25.02.2017 19:32-1Можно свою задачку для собеседования предложить? Если да, то вот есть массив
var s = [ ["a", "b"], "&&", ["сидели", "на трубе"], "||", "..." ]
Требуется получить
var r=[{'||':[{"&&:[["a", "b"],["сидели", "на трубе"]]},"..."]}]
Laney1
25.02.2017 19:33+36Зато сразу видно кто из кандидатов умеет самостоятельно размышлять
умеющий самостоятельно размышлять кандидат, увидев эти идиотские шарады, сразу встанет и уйдет
aamonster
25.02.2017 22:15Я бы спросил, что сделают с программистом, который закоммитит такой код. Возможно, ответ бы меня устроил :-)
Интересно, кстати, нанимают ли тех, кто этот вопрос не задал?
f0rk
25.02.2017 19:42+17Задачки забавные, и если бы мне подкинул такие коллега, я бы с удовольствием поразмышлял. Но на собеседовании — нет. Если честно, то возникает ощущение, что цель интервьюирующего — продемонстрировать свое превосходство, а не разобраться, полезен ли кандидат для компании.
rPman
25.02.2017 19:51+1Поставил плюс, в надежде, чтобы статья попала на главную, хочу больше мнений, надеюсь они будут такими же как выше — задачки интересные с академической точки зрения, но как задача на собеседовании может поставить завышенный барьер при выборе работника.
stargazr
25.02.2017 19:58+5Клоунада какая-то.
Вы думаете что ответили правильно на все вопросы? Советую убедиться в вашем браузере. Я думаю вы будете приятно удивлены!
Если я ошибся, что в этом для меня приятного? А если на все ответил верно, почему я должен быть удивлен выводу браузера? У автора явные проблемы с логикой, отсюда и задачки такие.
ruzhovt
25.02.2017 20:06+15Боже какой ужас. Правильный ответ к любому вопросу — да вы там совсем ё%нулись? встать и уйти
AlexZaharow
25.02.2017 20:25Вот и вам задачка. Требуется передать на сервер такой объект:
var a = {b:"B"} a.a=a;
Вам по силам это?f0rk
25.02.2017 22:24client:
msg = '() => { var a = {b:"B"}; a.a=a; return a; }'; send(msg);
server:
msg = receive(); res = eval(msg)();
staticlab
25.02.2017 22:30Ога-ога, эвалить на сервере строку с клиента :)
f0rk
25.02.2017 22:36+4Ога-ога, какой вопрос, такой и ответ. Если сильно хочется, можно свой eval написать, который парсит структуры типа
{b:"B",a:"reference(this)"}
, вариантов много придумать можно. Но вопрос был "Вам по силам это?", ответ — да, доказательство прилагается :)
AlexZaharow
25.02.2017 22:50По-другому никак. 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;
Да таким «простым» вопросом можно вообще любого кандидата резать. Без ножа.staticlab
26.02.2017 00:14Ну если серьёзно, то тут или вспомнить про второй параметр у JSON.stringify, а затем проверять, не встретился ли нам ранее такой объект, и подменить его каким-нибудь фиктивным {$ref: 1}, который затем надо будет корректно восстановить; или написать свой аналог stringify с аналогичной проверкой и дополнительным синтаксисом для ссылок на объекты.
iShatokhin
25.02.2017 23:10+3Можно сделать чуть безопасней (запретить доступ к локальной области видимости).
msg = receive(); res = new Function('msg', `return ${msg}`)();
iShatokhin
25.02.2017 23:28Опечатался, аргумент 'msg' там не нужен...
AlexZaharow
26.02.2017 01:04Интересно. Эту тонкость никогда не имел в виду! Буду знать. Спасибо.
iShatokhin
26.02.2017 02:33Клиентская часть
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).
iShatokhin
26.02.2017 03:00Небольшая опечатка —
new_a
надо заменить наobj
.
Результат можно проверить в консоли — https://jsfiddle.net/m5p2vz09/
ChALkeRx
26.02.2017 01:38+2Бесполезно это, потому что и из глобальной и в ноде и в браузере много чего можно наворотить.
Не надо евалить всё. Смотрите, как тот жеcycle
делает, хотя бы (хотя имхо это тоже так себе подход).iShatokhin
26.02.2017 02:42А если так?
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);
ChALkeRx
26.02.2017 04:55+2И снова нет.
Пример:
msg = "while(true){}"
, и всё, ваш сервер повис.
vm
— не способ запуска недоверенного кода.
wheercool
25.02.2017 23:19А где в условии сказано что сервер на js? :)
AlexZaharow
25.02.2017 23:49Сервер не обязательно на JS. Можно и Java/Nashorn.
iShatokhin
26.02.2017 00:01Так это ничего не поменяет, все тот же eval.
ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("nashorn"); engine.eval(msg); Object obj = engine.get("a");
p.s. несколько лет не писал на JAVA, могу и ошибиться
aamonster
25.02.2017 22:58Сам не яваскриптер, но полюбопытствовал в гугле — оказывается, есть как более-менее распространённые реализации в либах (типа dojo), так и довольно простой подход через второй аргумент JSON.stringify.
eval — стрёмно :-).
А в реальной жизни я бы постарался преобразовать граф в дерево.
ChALkeRx
25.02.2017 23:17https://www.npmjs.com/package/cycle же, ну.
Но если вам приходится кидаться такими объектами, то у вас в структуре, наверное, что-то не то.AlexZaharow
25.02.2017 23:36К счастью не пришлось. Передачу на сервер замутил чисто из академических интересов. Но обход структуры и поиск зацикливаний был. Среди прочего надо было получать список объектов для вотчеров коллекций ангуляра.
ChALkeRx
25.02.2017 23:41Но обход структуры и поиск зацикливаний был.
Это уже чуть другая задачка, заметно более простая.
См. https://github.com/davidmarkclements/fast-safe-stringify/blob/master/index.js, например.AlexZaharow
25.02.2017 23:46Норм. Но лично я упирался и хотел сохранить структуру объекта. А так куски кода до боли знакомы. ) Спасибо за ссылку.
bano-notit
26.02.2017 01:06Сделать конечно можно идиотским способом, но вопрос другой: зачем? Вот никогда не видел, чтобы такие циклические ссылки использовались где-то в проде. Может приведёте примерчик, где такие интереснейшие утечки люди используют?
wheercool
26.02.2017 11:03Любые графовые задачи. В общем случае граф может содержать циклы. Самый простой пример — моделирование карты.
Да, я в курсе, что можно использовать матрицу смежности, но не для всех типов алгоритмов она применима.
Кстати, матрица смежности, вроде как может решить проблему циклических ссылок, правда не эффективно )vintage
26.02.2017 11:12+1Есть и другие способы хранить граф. Например в виде словаря узлов и словаря связей.
Antelle
25.02.2017 20:59+1Мне страшно представить, каких людей вы набираете, предлагая такие задачки, какой код получаете в результате и для какой цели подобные вопросы задавать (у вас много такого кода?). Решается раз и навсегда запретом на такие штуки в линтере.
staticlab
25.02.2017 22:33-1Имхо даже линтер с минимальным набором правил просто пошлёт такой код куда подальше.
webinside
25.02.2017 21:32+4AlexZaharow
25.02.2017 22:56+1У моей жены есть подруга, которая хотела выйти замуж за умного. И одним из первых вопросов у неё было «А сколько у вас научных работ?». В итоге замуж вышла. За военного.
pinebit
25.02.2017 21:36+4Читаю такое и всякий раз радуюсь тому, что не работаю на «крупный банк». Хотя я знаю больше половины ответов, пишу себе спокойно примитивные конструкции на JavaScript, и зарабатываю больше, чем такие с позволения сказать «эрудиты». Коллеги хвалят за простой понятный код, заказчик исправно платит $, но да — нет в моем резюме всяких Сбертехов (точнее — есть, но больше не надо).
В последнее время я все больше разделяю политику интервью крупных IT компаний, которые просят развернуть список на доске/бумажке. В большинстве солидных компаний в которых мне довелось работать — почти везде были запрещены подобные задачи.
Так что да — встать и уйти, и не забыть написать отзыв.
urrri
25.02.2017 21:41Если рассматривать это как quiz, то задачки очень интересные. В основном только пост-фактум удается понять почему именно такой результат. Я, например, так и не понял в “ассемблерной” задачке, почему получается 0.
Если давать такое на интервью, то это большая ошибка. Любой человек нервничает на интервью, и даже понимая язык, вряд ли решит задачу правильно, даже более легкую. Да и вообще это не имеет смысла. Для проверки понимания языка не нужны такие навороты. Нужна проверка знаний основных нюансов языка, например всплытие функций или область видимости var. Это достигается более простыми задачками, но даже это не отражает способность человека думать.vintage
25.02.2017 22:41Сначала идёт постинкремент, а потом присваивание, очевидно. Но вот при чём тут ассемблер?
ZoomLS
25.02.2017 22:02Вы, наверное, ещё задаёте вопросы в духе — почему у колодцев крышки круглые и т.п.?
vintage
25.02.2017 22:05typeof document.createElement( 'object' )
Что вернёт и почему?
ChALkeRx
26.02.2017 00:08+1Ога.
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
И много других занимательных вещей смотрите в нашем КВН =).
У всех вышеперечисленных, кстати, простые объяснения, и они все гораздо менее упороты, чем задачки из собеседований на один из проектов крупного банка. Но на собеседовании я бы их задавать всё равно не стал.
SamSol
25.02.2017 22:18+1Очень хорошие примеры! Только вопрос должен быть другой: «Какие из этих фрагментов кода ты бы забраковал на код ревью»?
ChALkeRx
25.02.2017 23:19+1Но тогда стоило бы разбавить нормальными, потому что сейчас правильный ответ — «все».
Хотя вообще-то это даже до код ревью дойти не должно, линт такую ерунду на CI должен срезать.
staticlab
26.02.2017 00:17Линт такую ерунду уже при коммите должен срезать, если только раньше IDE с линтером хором материться не начали.
ChALkeRx
26.02.2017 00:23+1Линт такую ерунду уже при коммите должен срезать, если только раньше IDE с линтером хором материться не начали.
Это уже зависит от настроек на компьютере конкретного разработчика, каждый программирует, в чём хочет. В большинстве случаев — да, ещё до коммита. Но на CI это должно срезаться однозначно.
vintage
25.02.2017 22:44Кстати, я на собеседовании не задаю задачек вообще — по беседе и так быстро становится понятно насколько глубоко человек знаком с предметом. И, кстати, мы ищем фронтендеров в Питере — стучитесь в личку за подробностями :-)
jbubsk
25.02.2017 22:53+2Вы предлагаете это на один из проектов крупного банка? С вашим банком что-то не так.
Pakos
27.02.2017 10:32Это защита от исследователя скриптов — большинство сходит с ума и хохоча убегает в закат. К сожалению, не факт что в будущем так не сделает тот же интерпретатор JS и заберёт с собой в закат и работоспособный сайт.
justboris
27.02.2017 12:13Это как раз вряд ли. Все эти грабли хоть и странные, но описаны в стандарте, которому следуют все интерпретаторы. А зная, что нововведения в JS обычно делаются с обратной совместимостью, скорее всего ничего не сломается.
Aries_ua
25.02.2017 23:10Хочу добавить — никто не девелопит в стрессовой ситуации. А если она возникает, то стараются успокоится и расслабится, что бы лучше понимать, что надо делать.
Когда то на одном собеседовании предложили попрограмить на бумажке. Ну а что, тыжпрограммист! Конечно программить не стал и сказал им, что ребята — вы просто потратили мое время, а ваши тесты глупы. Начитались наверное у гугла, как собеседовать. Удачи вам.
Теперь к задачкам в статье — скажите, как они мне помогут определить, сможет ли человек найти общий язык со всеми в команде? Сможет ли человек разработать солюшен для какого ни буть компонента или модуля? Имеет ли человек какие нибудь наработки, к примеру во фронтенде? Делал ли человек что-то на других языках, кроме JS?
Могу еще накидать 10-к вопросов, которые я задаю на техническом собеседовании. Но не в них суть.
Дело в том, что ни один из вопросов статьи не ответит на мои поставленные вопросы.
Выше к комментариях верное замечание — «вредные советы».jodaka
26.02.2017 14:19Я Вам завидую, потому что фраза «никто не девелопит в стрессовой ситуации», мягко говоря, не для всех работает. Стрессовых ситуаций в моей практике встречается довольно много, и умение вести себя в них адекватно ничуть не менее важно, чем любой другой навык.
За последние несколько лет я побывал, наверное, на дюжине технических интервью. На половине из них были подобные вопросы. При этом, если Вас интервьюируют адекватные люди, то они сразу предупреждают, что цель вопросов — понять, насколько хорошо я знаю замыкания, асинхронную природу js, различные синтаксические конструкции и т.п. Т.е. вполне очевидно, что никто не собирается подобный код в продакшене использовать.
Интервью в компанию, в которой я сейчас работаю, включало подобные каверзные вопросы. А, когда я упомянул, что у меня был опыт разработки под андроид на Java, то мне предложили ещё и инвертировать односвязный список. Опять-же, всем было понятно, что никаких односвязных списков я в своей практике фронтэндера разворачивать не буду, но компания посчитала нужным оценить и эти знания.
Опять-же, мой опыт подсказывает, что подобные вопросы обычно составляют лишь часть технического интервью (как правило, незначительную). А вот в остальное время говорят как раз про опыт разработки, какие-то личные профессиональные интересы и т.п.
Aries_ua
26.02.2017 20:46По поводу стрессовой ситуации.
Когда они возникают, я стараюсь успокоить команду, расслабить. Хорошо идет к примеру покупка пиццы и 10-15 минутный перерыв с поеданием пиццы и выпиванием кофе с отвлеченными разговорами. Люди переключаются, отвлекаются от проблемы, а когда к ней возвращаются — то уже более трезво ее оценивают или находят другие пути решения.
Если у вас возникают постоянно стрессовые ситуации, значит вы что-то делаете не так.
northicewind
25.02.2017 23:37+1Это издевательство над кандидатами(если это не кандидат в модераторы govnokod.ru). Вместо того, чтоб узнать как у человека с алгоритмическим мышлением, опытом в решении прикладных задач и возможностью поиска решения возникающих проблем, вы кидаете ему в голову это…
bano-notit
26.02.2017 01:10Вот мне интересно. И много у Вас людей ответило на все эти задачки? Мне кажется, что нет. А ещё мне интересно, Вы сами использовали это в реальной работе?
Вот лично я такие неявности не использовал, да и вообще, использовать неявные конструкции языка — мовитон. Ибо за такой код и руки могут оторвать, потому что он работает совершенно не так, как видится.
Прикольно будет, когда у Вас в проекте будет баг из-за такой вот вещи, потому что кандидат подумал, что такие конструкции неплохо бы использовать в реальной жизни.
bioroot
26.02.2017 12:00-1Вспоминается олдскульная шутка — писать на Perl можно на любом языке. А из задач с подковыркой моя любимая:
if (a != a) { alert(a); }
Вопрос: существует ли такое a, при котором мы увидим алерт? Как ни странно, даже опытные js-программисты не всегда могут ответить на этот вопрос.vintage
26.02.2017 12:37+4Опытные jquery-программисты, выхотели сказать?
bioroot
26.02.2017 13:11Если бы. В jQuery про это с давних времён написано в мануале: NaN_and_Infinity. Технология тут не при чём. Просто многие изучают язык (любой) сразу садясь за высокоуровневый фреймворк и в лучшем случае читают про фундамент языка по диагонали.
vintage
26.02.2017 13:31+5Ёсли бы jquery-программисты читалимануалы… их бы называли js-программистами :-)
tarasikgoga
26.02.2017 23:00-1var a = b = true, c = (a) => a; (function a(a = c(b).a = c = () => a) { return a(); })()
Используете стеролчные ф-ции но при этом объявляете переменные с помощью var?Aingis
27.02.2017 10:37+1«Объявляете» — это громко сказано. Переменная
b
так вообще не объявлена. И этим страдают многие примеры.
DexterHD
Сразу наталкивает на размышления, какое прикладное значение имеет весь этот код?
Мне кажется ни какого, потому что в продакшене так не пишут. А если пишут надо бить молотком по рукам. IMHO всегда думал что на собеседовании нужно узнать прежде всего будет ли кандидат полезен компании или нет, и сможет ли он решать проблемы бизнеса или нет, а тут проблемами бизнеса и не пахнет. Какой смысл задрачивать идиотские особенности JS и как это задротсво поможет решать проблемы?
Напомнило высказывание автора Homebrew. Хотя оно немного не об этом, но из той же оперы я считаю.
stargazr
А правда ли, что Google уже поменял свою точку зрения?
Вроде бы кто-то оттуда писал, что умение решать олимпиадные задачки не говорит об умении писать промышленный код.