Пять типичных вопросов по JavaScript при собеседовании на работу

Сколько угодно.

  • Нужно алертом вывести какое-то сообщение, спустя 3 секунды после запуска скрипта. Как это сделать?

Так:

Или так:

  • Чем отличается наследование в JavaScript от наследования в PHP?

В отличие от PHP, где наследование можно делать одним способом, в JavaScript таких способов много. На уровне языка реализовано наследование на прототипах.

В JavaScript каждый объект может иметь ассоциацию с другим объектом - так называемый "прототип" (prototype). В случае, если поиск некоторого свойства (или метода) в исходном объекте заканчивается неудачно, интерпретатор пытается найти одноименное свойство (метод) в его прототипе, затем - в прототипе прототипа и т. д. К примеру, если мы затребовали обращение к obj.prop (или, что абсолютно то же самое, obj["prop"]), JavaScript начнет искать свойство prop в самом объекте obj, затем – в прототипе obj, прототипе прототипа obj, и так до конца.

  • Приведи пример наследования в JavaScript.

Например, пусть объект "cat" наследуется от объекта "animal". В наследовании на прототипах это реализуется как ссылка

Или вот чуть более развернутый пример. MyType наследуется от Obj:


  • Пара слов об объектах в JavaScript?

Объекты (они же - ассоциативные массивы, хэши) и работа с ними в JavaScript реализованы не так, как в большинстве языков. Объект в JavaScript представляет собой обычный ассоциативный массив или, иначе говоря, "хэш". Он хранит любые соответствия "ключ => значение" и имеет несколько стандартных методов.

  • Что представляет из себя метод объекта в JavaScript?

Метод объекта в JavaScript - это просто функция, которая добавлена в ассоциативный массив.

  • Зачем в JavaScript перед переменной писать var?

Если создавать переменную через обычное присваивание - будет создана "глобальная переменная". Пример:

Если создавать переменную с использованием слова var, тогда будет создана "локальная переменная", которая перестаёт существовать после завершения работы функции. Пример:

  • Есть две функции: function f(a,b) { return a+b } и var f = function(a,b) { return a+b }. Есть ли между ними разница? Если есть то какая?

Есть, разница в видимости функции. Вариант функции без var виден везде в текущей области видимости. В том числе и до самого определения функции. Вариант с var присваивает функцию переменной, поэтому такая функция видна только после определения.

  • Как создать массив в JavaScript?

Вот несколько способов.

  • Можно ли в JavaScript использовать функцию в качестве конструктора?

Вот так:

  • Сколько и какие конструкции для циклов есть в JavaScript?

Три: for, while и do...while.

  • Что cделает код: break mark; ?

Выйдет из текущего блока цикла или switch на метку " mark ".

  • Можно ли задать массив таким образом: var a = "a,b".split(",")?

Да, можно.

  • Что выведет alert(typeof null); ?

Выведет сообщение "object".

  • А это: alert(null instanceof Object); ?

Выведет сообщение "false".

  • 0.1 + 0.2 == 0.3 ?

Нет, т.к. вычисленное значение будет равно 0.30000000000000004. Это действие точности вычислений и проявляется она не только в JavaScript.

  • Что выведет alert(typeof NaN); ?

"Number"

  • Что выведет alert(NaN === NaN); ?

"false"

  • В чём различие свойств innerHTML и outerHTML?

Свойство любого DOM элемента innerHTML содержит HTML код, который находится внутри этого элемента. При установке нового значения этого свойства, внутренний HTML код рендерится браузером заново.

outerHTML почти аналогичен innerHTML, разница в том, что он возвращает полный HTML элемента.

Также, важно отметить, что innerHTML поддерживается всеми современными браузерами, а outerHTML поддерживается в IE (с некоторыми отличиями от остальных браузеров), в последних версиях Opera, и в браузерах на основе последних WebKit (Safari, Chrome), но не поддерживается в Firefox.

Для кода:

innerHTML возвратит:

outerHTML возвратит:


  • Какая разница между операторами == и ===?

Оператор == сравнивает на равенство, а вот === сравнивает на идентичность. Плюс оператора === состоит в том, что он не приводит два значения к одному типу. Именно из-за этого он обычно и используется.

  • В чем разница между Object.getOwnPropertyNames() и Object.keys()?

Object.getOwnPropertyNames() возвращает перечислимые и не перечислимые свойства из объекта или массива.

Object.keys() возвращает перечислимые свойства из объекта или массива.

  • С помощью какой конструкции языка можно управлять потоком выполнения скрипта и отслеживать ошибки?

Это возможно с помощью конструкции try{}... catch{}

  • Почему вызов a(); происходит успешно, а вызов b(); выдает ошибку?

Функция а() инициализируется на этапе загрузки скрипта, как бы "всплывает вверх" а функция б инициализируется, когда объявляется переменная b

  • Что такое глобальные переменные? Как они создаются? Какие проблемы связаны с использованием глобальных переменных?

Глобальная переменная - переменная, которая доступна (видима) во всем документе, в отличии от локальной (ограничена рамками блока программного кода, внутри которого она определена)

Большинство JavaScript разработчиков избегает использования глобальных переменных. Одна из причин - возможный конфликт имен глобальных и локальных переменных. Так же код использующий глобальные переменные может быть тяжелее сопровождать и тестировать.

  • Что такое замыкания (closure) в JavaScript?

Простыми словами это внутренняя функция, т.е. функция в функции.

Замыканием (closure) называют потому, что после выполнения родительской или внешней функции, код внутренней все еще "живет" в интерпретаторе, и его можно выполнить. Ошибок не возникнет даже если внутренняя функция (замыкание) будет использовать переменные из внешней функции. Например, эту особенность можно использовать для создания функций обработчиков событий:


  • Напишите функцию принимающую строку с именем файла и возвращающую расширение (фрагмент после последней точки).

    • Что такое prototype в javascript?

    В общих чертах prototype - это свойство позволяющее добавлять уже существующим объектам свойства, также используется для эмуляции наследования классов в JavaScript. Подробный ответ написан здесь. Еще как вариант, можно упомянуть о Prototype.js. Это популярная библиотека добавляющая удобные ООП возможности в программы на JavaScript-е.

    • Какие способы навешивания обработчиков событий вы знаете?

    События можно добавлять тремя способами:

    • htmlElement.onclick = function(event) { .... } - так можно добавить только один обработчик
    • htmlElement.addEventListener("click", ...) - так можно навесить несколько обработчиков, сохраняет порядок обработчиков
    • htmlElement.attachEvent("on"+имя_события, обработчик) - тоже можно навесить несколько, не сохраняет порядок обработчиков, нет доступа к элементу на котором сработало событие.

Разработчики JavaScript пользуются большим спросом в мире IT. Если это та сфера, в которой у вас достаточно знаний, у вас есть много возможностей изменить место своей работы и повысить заработную плату. Но прежде чем вы будете приняты на работу, вам необходимо будет пройти собеседование. В этой статье мы покажем вам 5 типичных вопросов, которые вы должны пройти при приёме на работу и показать свои умения в JavaScript.

Вопрос 1: Возможности

Рассмотрим следующий код:

(function() { var a = b = 5; })(); console.log(b);

Что будет написано на консоли?

Ответ

Код выше напишет 5.

Хитрость этого вопроса заключается в том, что в IIFE есть два задания, но переменная a объявляется ключевым словом var. Это означает, что a является переменной функции. b же присвоена глобальной области.

Другой хитростью этого вопроса является то, что он использует строгий режим ("use strict";) в функции. Если был включен строгий режим, код покажет ошибку “Uncaught ReferenceError: b не определён”. Помните, что строгий режим требует, чтобы вы ссылались на глобальные области. Таким образом, вы должны написать:

(function() { "use strict"; var a = window.b = 5; })(); console.log(b);

Вопрос 2: Создание “родных” методов

Определите повторяющуюся функцию в строке объекта. Функция подразумевает целое число, определяющее, сколько раз строка должна повториться. Функция повторяет указанную строку указанное количество раз. Например:

Console.log("hello".repeatify(3));

Должно получиться "hellohellohello".

Ответ

Возможная реализация показана ниже:

String.prototype.repeatify = String.prototype.repeatify || function(times) { var str = ""; for (var i = 0; i < times; i++) { str += this; } return str; };

Вопрос проверяет знания разработчиков о наследовании в JavaScript и свойстве прототипа. Так же проверяется и способность разработчика расширять функциональность собственных типов данных (хотя это не обязательно).

Ещё одним важным моментом является демонстрация знаний о том, как не отменить уже определенные функции. Это делается путём тестирования, подтверждающего, что функция не существует самостоятельно до ее определения.

String.prototype.repeatify = String.prototype.repeatify || function(times) {/* code here */};

Этот метод особенно полезен, когда вас попросили заклинить функцию JavaScript.

Вопрос 3: Подъём

Каков результат выполнения и почему?

Function test() { console.log(a); console.log(foo()); var a = 1; function foo() { return 2; } } test();

Ответ

Результаты кода - underfined и 2.

Причина в том, что обе переменные функции подняты (помещены в верхней части функции), но переменные не удерживают присвоены значения. В то время, когда переменная a печатается, она существует в функции (это декларируется), но она все ещё undefined. Другими словами, код выше эквивалентен следующему:

Function test() { var a; function foo() { return 2; } console.log(a); console.log(foo()); a = 1; } test();

Вопрос 4: Как это работает в JavaScript

Каков результат следующего кода? Обоснуйте свой ответ.

Var fullname = "John Doe"; var obj = { fullname: "Colin Ihrig", prop: { fullname: "Aurelio De Rosa", getFullname: function() { return this.fullname; } } }; console.log(obj.prop.getFullname()); var test = obj.prop.getFullname; console.log(test());

Ответ

Код выдаст Aurelio De Rosa и John Doe. Причина в том, что контекст функции, вызываемый ключевым this словом, в JavaScript зависит от того, как именно вызывается функция, а не от того, как она определена.
Вызов первых console.log (), getFullname () вызывается функцией объекта obj.prop. Таким образом, контекст относится к последнему и возвращает “fullname” как свойство объекта. В противном случае, когда getFullname () присваивается переменной, контекст относится к глобальному объекту. Это происходит потому, что тест устанавливается как свойство глобального объекта (window). По этой причине функция возвращает значение свойства fullnameиз window, которая в данном случае является кодом, устанавливаемым в первой строке фрагмента.

Вопрос 5: call () и apply ()

Исправьте предыдущий вопрос так, чтобы последний console.log () стал Aurelio De Rosa.

Ответ

Вопрос может быть изменен, повлияв на контекст функции, используя функции call () или apply (). Если вы не знаете их и их отличия, вам стоит прочесть статью. В коде ниже я буду использовать call (), но в этом случае применяется apply (), результат будет тот же:

Console.log(test.call(obj.prop));

Заключение

Доброго времени суток, дорогой гость! Рада приветствовать на страницах своего блога.

Сегодня речь пойдет о том, какие вопросы задаются на техническом собеседовании кандидату на позицию Javascript-разработчика. Цель — проверить необходимый уровень знаний языка кандидата и теоретической подготовки.

Мне бы хотелось выразить благодарность Senior Frontend Developer Греченок Евгению и Senior Backend Developer Гиззатову Марселю за помощь в создании статьи. Те вопросы, которые идут дальше, из их методички, которую они используют для собеседований кандидатов «и на 30 тысяч, и на 130». Большое спасибо, ребята, за время, которое мне уделили, и считаю, что для меня на собеседовании был хороший стимул убрать пробелы в собственных знаниях и сделать еще один шаг к тому, чтобы стать профессионалом.

Вопросы по JavaScript (синтаксис и особенности языка)

1. Если вам необходимо проверить, определено ли свойство у самого объекта … (hasOwnProperty)
2. Как работает this (http://bonsaiden.github.io/JavaScript-Garden/ru/#function.this)
3. Замыкания (http://bonsaiden.github.io/JavaScript-Garden/ru/#function.closures)
4. Определение переменных (всплытие)
5. Переменные let, const, var (https://learn.javascript.ru/let-const)
6. Равенство и сравнение (оператор == и ===)
7. Операторы typeof и instanceof (для чего используются http://bonsaiden.github.io/JavaScript-Garden/ru/#types.instanceof)
8. Почему нельзя использовать eval (http://bonsaiden.github.io/JavaScript-Garden/ru/#core.eval)
9. Деструктуризация (https://learn.javascript.ru/destructuring)
10. Строки-шаблоны (https://learn.javascript.ru/es-string)
11. Классы (прототипы, современные)
12. Итераторы (https://learn.javascript.ru/iterator)
13. Генераторы (https://learn.javascript.ru/generator)
14. Новые типы данных (https://learn.javascript.ru/set-map)
15. Что такое Eventloop? Объясните принцип его работы.

Общие вопросы по программированию

  1. Отличие компилируемого языка от интерпретируемого
    Чем компиляция С отличается от Java
  2. Отличие статической типизации от динамической
  3. Отличие наследование от композиции (https://habrahabr.ru/post/325478/)
  4. Алгоритмы и их сложность (JS https://tproger.ru/translations/algorithms-and-data-structures/)
    a. В приложении к любому языку привести примеры стандартных методов сортировки / обхода дерева / поиска в массиве, дикте с пояснением о их сложности и как работают.
  5. FIFO, LIFO
  6. Структуры данных (JS https://learn.javascript.ru/data-structures)
    a. Числа, Строки
    b. Объекты (ассоциативные массивы), передача по ссылке (что передаётся по значению)
    c. Массивы
    d. Деревья, Списки (связанный, ссылочный)
  7. Архитектура (в чём разница)
    a. асинхронная,
    b. многопоточная
  8. Микросервисы
    a. Будет ли микросервисами распределённая архитектура через общую шину данных
    b. Требования к микросервисам
    i. горизонтальное масштабирование
    ii. отказоустойчивость
  9. Преимущества микросервисов:
    i. легкая поддержка (небольшие сервисы легче)
    ii. нет ограничения на языки и библиотеки для решения задачи
    iii. упрощенное тестирование, возможность замокать взаимодействия
    iv. легкое накатывание и откатывание новых версий
    v. можно экспериментировать с технологиями

Гибкие методологии

  1. Зачем нужны
  2. Какие подходы есть
  3. Выявление проблем в разработке, зачем нужна ретроспектива в scrum
  4. Распределение задач по разработчикам
    • горят сроки
    • планирование

И напоследок...

Задача на понимание JavaScript

Задача 1. Что выведет данный код?

Var b = 5; var a = function() { alert(b); }; a();

Цель задачи: проверить понимание замыкания.

Тема: Замыкание (closure).

Ответ: Если исходить из определения замыкания — способность функции запоминать область видимости переменной, в которой та была объявлена, то правильный ответ 5. Функция a запомнила содержимое объявленной ранее переменной за пределами функции, и после вывода функции, передала в alert 5.

На собеседованиях часто любят задавать однотипные вопросы, ответы на которые уже давно выучены.

Сегодня же мы рассмотрим те вопросы, про которые вспоминают достаточно редко.

И так, начнём!

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.

  • 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) // 5 add(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]);

Что же происходит? Когда у объекта устанавливается новое свойство, то JavaScript неявно сделает stringify значения. В коде выше b и c являются объектами, следовательно они оба конвертируются в "" (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. Объедините два массива с вложенностью

], ] ->

Задачу можно решать различными способами. Обычно хотят узнать знает ли собеседуемый такой метод как reduce .

Идея заключается в том, чтобы обойти все элементы исходного массива и его “под массивов” с целью вернуть найденные значения в новый массив. Это происходит рекурсивно пока мы не дойдём до последнего элемента.

Так же с формированием нового массива нам помогает concat .

Const flatten = (arr) => arr.reduce((flat, toFlatten) => flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten), );

На этом всё! 🙏🏼 👍



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: