Вопросы на собеседовании для JavaScript-программиста

Хочешь уверенно проходить IT-интервью?

Готовься к IT-собеседованиям уверенно с AI-тренажёром T1!

Мы понимаем, как сложно подготовиться: стресс, алгоритмы, вопросы, от которых голова идёт кругом. Но с AI тренажёром всё гораздо проще.

💡 Почему Т1 тренажёр — это мастхэв?

  • Получишь настоящую обратную связь: где затык, что подтянуть и как стать лучше
  • Научишься не только решать задачи, но и объяснять своё решение так, чтобы интервьюер сказал: "Вау!".
  • Освоишь все этапы собеседования, от вопросов по алгоритмам до диалога о твоих целях.

Зачем листать миллион туториалов? Просто зайди в Т1 тренажёр, потренируйся и уверенно удиви интервьюеров. Мы не обещаем лёгкой прогулки, но обещаем, что будешь готов!

Реклама. ООО «Смарт Гико», ИНН 7743264341. Erid 2VtzqwP8vqy


Предлагаем вашему вниманию широкий список вопросов, которые могут задать на собеседовании JavaScript-программисту. Все задачи решены на JS, ES5 и ES6.

После каждого решения приведена ссылка на Codepen, где вы можете самостоятельно опробовать решение конкретной задачи.

Массивы

1.1 У вас есть массив целых чисел, найдите наибольшее произведение из трёх чисел данного массива.

var unsortedArray = [-10, 7, 29, 30, 5, -10, -70];

computeProduct(unsortedArray); // 21000

function sortIntegers(a, b) {
  return a - b;
}

// Наибольшее произведение - это (min1 * min2 * max1 || max1 * max2 * max3)
function computeProduct(unsorted) {
  var sortedArray = unsorted.sort(sortIntegers),
    product1 = 1,
    product2 = 1,
    array_n_element = sortedArray.length - 1;

  // Получаем произведение трёх наибольших элементов уже отсортированного массива
  for (var x = array_n_element; x > array_n_element - 3; x--) {
      product1 = product1 * sortedArray[x];
  }

  product2 = sortedArray[0] * sortedArray[1] * sortedArray[array_n_element];

  if (product1 > product2) return product1;

  return product2;
}

Решение на Codepen: https://codepen.io/kennymkchan/pen/LxoMvm?editors=0012

Нахождение пропущенного элемента

1.2 Неотсортированный массив содержит (n-1) чисел из последовательности {1,2,...,n} (границы определены), найдите недостающий элемент массива за время o(n).

// Число, возвращаемое функцией - 8
var arrayOfIntegers = [2, 5, 1, 4, 9, 6, 3, 7];
var upperBound = 9;
var lowerBound = 1;

findMissingNumber(arrayOfIntegers, upperBound, lowerBound); // 8

function findMissingNumber(arrayOfIntegers, upperBound, lowerBound) {
  // Проходим через массив и находим сумму чисел
  var sumOfIntegers = 0;
  for (var i = 0; i < arrayOfIntegers.length; i++) {
    sumOfIntegers += arrayOfIntegers[i];
  }

  /* Находим теоретическую сумму последовательных чисел, используя вариацию суммы Гаусса*/
  // Формула: [(N * (N + 1)) / 2] - [(M * (M - 1)) / 2];
  // N - верхняя граница, а M - нижняя граница

  upperLimitSum = (upperBound * (upperBound + 1)) / 2;
  lowerLimitSum = (lowerBound * (lowerBound - 1)) / 2;

  theoreticalSum = upperLimitSum - lowerLimitSum;

  return theoreticalSum - sumOfIntegers;
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/rjgoXw?editors=0012

Удаление повторяющихся значений

1.3 Удалите все одинаковые значения в массиве, возвращая массив, состоящий из уникальных элементов.

// Реализация на ES6
var array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];

Array.from(new Set(array)); // [1, 2, 3, 5, 9, 8]

// Реализация на ES5
var array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];

uniqueArray(array); // [1, 2, 3, 5, 9, 8]

function uniqueArray(array) {
  var hashmap = {};
  var unique = [];

  for(var i = 0; i < array.length; i++) {
    /* Если возвращаемое значение (unique) - undefined, то оно приравнивается к false. */
    if(!hashmap.hasOwnProperty(array[i])) {
      hashmap[array[i]] = 1;
      unique.push(array[i]);
    }
  }

  return unique;
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/ZLNwze?editors=0012

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

var array = [7, 8, 4, 9, 9, 15, 3, 1, 10];
// [7, 8, 4, 9, 9, 15, 3, 1, 10] возвращаемое значение будет `11`, как разница между `4` и `15`
// Примечание: это не `14`, как разница между `15` и `1`, так как 15 стоит перед 1.

findLargestDifference(array);

function findLargestDifference(array) {
  // Если в массиве всего один элемент, то задача не имеет смысла
  if (array.length <= 1) return -1;

  // currentMin будет отвечать за наименьший элемент
  var currentMin = array[0];
  var currentMaxDifference = 0;

  // Мы будем проходить по массиву раз за разом, находя наибольшую разность
  // Записываем наименьший элемент, так как он впоследствии нам пригодится

  for (var i = 1; i < array.length; i++) {
    if (array[i] > currentMin && (array[i] - currentMin > currentMaxDifference)) {
      currentMaxDifference = array[i] - currentMin;
    } else if (array[i] <= currentMin) {
      currentMin = array[i];
    }
  }

  // Если разность равна нулю или меньше нуля, то задача не имеет смысла
  if (currentMaxDifference <= 0) return -1;

  return currentMaxDifference;
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/MJdLWJ?editors=0012

И ещё задачи на массивы

1.5 У вас есть массив целых чисел, выведите такой массив, что output[i] равен произведению всех элементов массива за исключением i-ого. (Решите за O(n) без операции деления).

var firstArray = [2, 2, 4, 1];
var secondArray = [0, 0, 0, 2];
var thirdArray = [-2, -2, -3, 2];

productExceptSelf(firstArray); // [8, 8, 4, 16]
productExceptSelf(secondArray); // [0, 0, 0, 0]
productExceptSelf(thirdArray); // [12, 12, 8, -12]

function productExceptSelf(numArray) {
  var product = 1;
  var size = numArray.length;
  var output = [];

  // Из первого массива: [1, 2, 4, 16]
  // В данном случае, последний элемент находится уже на правильном
  // месте, чтобы просто умножить его на 1 в следующем шаге
  for (var x = 0; x < size; x++) {
      output.push(product);
      product = product * numArray[x];
  }

  var product = 1;
  for (var i = size - 1; i > -1; i--) {
      output[i] = output[i] * product;
      product = product * numArray[i];
  }

  return output;
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/OWYdJK?editors=0012

Пересечение двух массивов

1.6 Найдите пересечение двух массивов. Пересечение - это общие элементы, которые присутствуют в обоих массивах. Элементы должны быть уникальны.

var firstArray = [2, 2, 4, 1];
var secondArray = [1, 2, 0, 2];

intersection(firstArray, secondArray); // [2, 1]

function intersection(firstArray, secondArray) {
  /* Здесь логика состоит в том, чтобы создать hashmap с элементами 
первого массива в качестве ключей */
  /* После этого вы можете проверить, существует ли элемент в хэше.
 Сделать это можно за время O(1) благодаря hashmap */
  // Если элемент существует, то добавляем его к новому массиву

  var hashmap = {};
  var intersectionArray = [];

  firstArray.forEach(function(element) {
    hashmap[element] = 1;
  });

  secondArray.forEach(function(element) {
    if (hashmap[element] === 1) {
      intersectionArray.push(element);
      hashmap[element]++;
    }
  });

  return intersectionArray;

}

Решение на Codepen: http://codepen.io/kennymkchan/pen/vgwbEb?editors=0012

Строки

2.1 У вас есть строка. Ваша задача - перевернуть каждое слово в строке. "Welcome to this Javascript Guide!" должно стать "emocleW ot siht tpircsavaJ !ediuG".

var string = "Welcome to this Javascript Guide!";

// Вывод будет таким: "!ediuG tpircsavaJ siht ot emocleW"
var reverseEntireSentence = reverseBySeparator(string, "");

// Вывод будет таким: "emocleW ot siht tpircsavaJ !ediuG"
var reverseEachWord = reverseBySeparator(reverseEntireSentence, " ");

function reverseBySeparator(string, separator) {
  return string.split(separator).reverse().join(separator);
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/VPOONZ?editors=0012

2.2 У вас есть две строки. Определите, являются ли они анаграммами друг к другу. "Mary" - анаграмм к "Army".

var firstWord = "Mary";
var secondWord = "Army";

isAnagram(firstWord, secondWord); // true

function isAnagram(first, second) {
  // Для удобства переведём все символы в нижний регистр
  var a = first.toLowerCase();
  var b = second.toLowerCase();

  /* Отсортируем строки и присоединим финальный массив к строкам. Сравним результаты */
  a = a.split("").sort().join("");
  b = b.split("").sort().join("");

  return a === b;
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/NdVVVj?editors=0012

2.3 Проверьте, является ли строка палиндромом. "racecar" - палиндром. "race car" должен тоже считаться за палиндром. Регистр должен учитываться.

isPalindrome("racecar"); // true
isPalindrome("race Car"); // true

function isPalindrome(word) {
  // Уберём все символы, не являющиеся буквами
  var lettersOnly = word.toLowerCase().replace(/\s/g, "");

  // Сравним строку с её перевёрнутой версией
  return lettersOnly === lettersOnly.split("").reverse().join("");
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/xgNNNB?editors=0012

Изоморфные строки

2.4 Проверьте, являются ли две строки изоморфными.
Две строки называются изоморфными, когда в строке A можно заменить конкретный символ на любой другой для получения строки B. Порядок символов должен остаться неизменным. Каждый последовательный символ в строке A сравнивается с каждым последовательным символов в строке B.

'paper' и 'title' вернёт true (p = t, a = i, e = l, r = e).

'egg' и 'sad' вернёт false.

'dgg' и 'add' вернёт true.

isIsomorphic("egg", 'add'); // true
isIsomorphic("paper", 'title'); // true
isIsomorphic("kick", 'side'); // false

function isIsomorphic(firstString, secondString) {

  /* Проверка на то, имеют ли две строки одинаковую длину. Если нет, то они не изоморфны по определению. */
  if (firstString.length !== secondString.length) return false

  var letterMap = {};

  for (var i = 0; i < firstString.length; i++) {
    var letterA = firstString[i],
        letterB = secondString[i];

    if (letterMap[letterA] === undefined) {
      letterMap[letterA] = letterB;
    } else if (letterMap[letterA] !== letterB) {
      /* Если letterA уже существует, но не указывает на letterB, 
это значит, что A указывает на больше чем одну букву в строке B. */
      return false;
    }
  }
  // Если программа вышла из цикла, значит все условия соблюдены!
  // Две строки изоморфны!
  return true;
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/mRZgaj?editors=0012

Стэки и очереди

3.1 Реализуйте два метода: enqueue и dequeue, используя только два стэка

var inputStack = []; // Первый стэк
var outputStack = []; // Второй стэк

// Для реализации enqueue просто сделаем push в первый стэк
function enqueue(stackInput, item) {
  return stackInput.push(item);
}

function dequeue(stackInput, stackOutput) {
  /* Перевернём стэк таким образом, что первый элемент выходного 
стэка - последний элемента входного. После этого делаем pop выходного стэка */
  if (stackOutput.length <= 0) {
    while(stackInput.length > 0) {
      var elementToOutput = stackInput.pop();
      stackOutput.push(elementToOutput);
    }
  }

  return stackOutput.pop();
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/mRYYZV?editors=0012

3.2 Напишите функцию, которая будет проверять, являются ли фигурные скобки сбалансированными, используя стэки. {} - считается блоком. {}{} - сбалансированные скобки. {{{}} - несбалансированные.

var expression = "{{}}{}{}"
var expressionFalse = "{}{{}";

isBalanced(expression); // true
isBalanced(expressionFalse); // false
isBalanced(""); // true

function isBalanced(expression) {
  var checkString = expression;
  var stack = [];

  // Если входная строка пуста, то технически всё сбалансировано
  if (checkString.length <= 0) return true;

  for (var i = 0; i < checkString.length; i++) {
    if(checkString[i] === '{') {
      stack.push(checkString[i]);
    } else if (checkString[i] === '}') {
      if (stack.length > 0) {
        stack.pop();
      } else {
        return false;
      }
    }
  }

  if (stack.pop()) return false;
  return true;
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/egaawj?editors=0012

Рекурсия

4.1 Напишите рекурсивную функцию, которая переводит десятичное число в двоичное. Если входное число - 4, выходным будет 100.

decimalToBinary(3); // 11
decimalToBinary(8); // 1000
decimalToBinary(1000); // 1111101000

function decimalToBinary(digit) {
  if(digit >= 1) {
    if (digit % 2) {
      return decimalToBinary((digit - 1) / 2) + 1;
    } else {
      return decimalToBinary(digit / 2) + 0;
    }
  } else {
   
    return '';
  }
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/OWYYKb?editors=0012

4.2 Напишите рекурсивную функцию, которая выполняет бинарный поиск

function recursiveBinarySearch(array, value, leftPosition, rightPosition) {
  // Value DNE
  if (leftPosition > rightPosition) return -1;

  var middlePivot = Math.floor((leftPosition + rightPosition) / 2);
  if (array[middlePivot] === value) {
    return middlePivot;
  } else if (array[middlePivot] > value) {
    return recursiveBinarySearch(array, value, leftPosition, middlePivot - 1);
  } else {
    return recursiveBinarySearch(array, value, middlePivot + 1, rightPosition);
  }
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/ygWWmK?editors=0012

Числа

5.1 У вас есть целое число, определите, является ли оно является степенью двойки.

isPowerOfTwo(4); // true
isPowerOfTwo(64); // true
isPowerOfTwo(1); // true
isPowerOfTwo(0); // false
isPowerOfTwo(-1); // false

//Без проверки на ноль
function isPowerOfTwo(number) {
  // `&` ипользует побитовую запись n.
  // В данном случае, входное число - 4; выражение идентично:
  // `return (4 & 3 === 0)`
  /* 4 в двоичном виде - 100, а 3 - 011. & 
проверяет на то, чтобы оба числа в двоичном виде имели еденицу на одном и том же месте.
В таком случае будет возвращено 1, иначе - 0. В этом случае, результатом будет 000. */
  // таким образом, 4 удовлетворяет условиям.

  return number & (number - 1) === 0;
}

//С проверкой на ноль
function isPowerOfTwoZeroCase(number) {
  return (number !== 0) && ((number & (number - 1)) === 0);
}

Решение на Codepen: http://codepen.io/kennymkchan/pen/qRGGeG?editors=0012

JavaScript

6.1 Объясните, что такое "поднятие" в JavaScript.

"Поднятие" - это правило, которое подразумевает под собой необходимость перемещать все объявления переменных в вершину конкретного блока кода. Это касается объявления переменных, инициализация же может проходить и дальше в коде.

6.2 Объясните функционал директивы use strict;

директива use strict; говорит о том, что код должен быть выполнен в "строгом режиме". Один из плюсов данного режима - это то, что он предотвращает использование необъявленных переменных. Наиболее старые версии JavaScript будут игнорировать данную директиву.

// Пример "строгого режима"
"use strict";

catchThemAll();
function catchThemAll() {
  x = 3.14; // На этом моменте будет ошибка
  return x * x;
}

6.3 Объясните, что такое event bubbling и как его предотвратить.
Even bubbling - это концепт, при котором порядок выполнения событий должен подниматься по структуре DOM-дерева.

Один из вариантов предотвращения - "event.stopPropagation()" или "event.cancelBubble", для IE версии ниже 9.

6.4 Какова разница между == и === в JavaScript?

=== известен как строгий оператор. Ключевая разница между == и === - это то, что == сравнивает лишь значения, а === - ещё и типы данных.

// Пример "==" и "===".
0 == false; // true
0 === false; // false

2 == '2'; // true
2 === '2'; // false

6.5 Какова разница между null и undefined?

Null в JavaScript может быть присвоен переменной, а undefined лишь показывает, что переменная была объявлена, но не была инициализирована.

6.6 В чём разница между прототипным наследованием и классическим наследованием?

В классическом наследовании классы неизменны, поддерживают множественное наследование, могут содержать интерфейсы, final классы и abstract классы. Прототипы же куда более гибки в том плане, что они могут быть изменены.

Другие статьи по теме

Подборка материалов по JavaScript

10 вещей, которые стоит знать каждому JavaScript-разработчику

Комментарии

ВАКАНСИИ

Добавить вакансию
Golang-разработчик
Пермь, по итогам собеседования
Hotel Search Team Lead (Golang)
по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ