Основы языка
Значения и типы
Значения (values) в JavaScript имеют типы, а переменные, в которых лежат эти значения — не имеют.
Встроенные типы данных:
Оператор typeof
Оператор typeof
получает некоторое значение и определяет его тип:
let a;
typeof a; // "undefined"
a = "hello world";
typeof a; // "string"
a = 42;
typeof a; // "number"
a = true;
typeof a; // "boolean"
a = null;
typeof a; // "object" - известный баг JS
a = undefined;
typeof a;// "undefined"
a = { b: "c" };
typeof a; // "object"
Приведение типов (coercion)
Конвертация встроенных типов данных друг в друга в JavaScript называется приведением типов (coercion). Оно бывает явное (explicit) и неявное (implicit).
Пример явного приведения:
let a = "42"; // строка
let b = Number(a);
a; // "42" - строка
b; // 42 - число
Пример неявного приведения:
let a = "42"; // строка
let b = a * 1; // строка "42" неявно приводится к числу
a; // "42" - строка
b; // 42 - число
Особенно важно понимать, как происходит приведение к логическому типу, так как оно часто происходит в условиях.
Следующие значения приводятся к false:
- «» (пустая строка)
- 0, -0, NaN
- null, undefined
- false
А эти — к true:
- «hello» (любая непустая строка, даже » » — строка с пробелом)
- 42 (число, отличное от нуля)
- true
- [ ], [ 1, «2»] (любой массив, даже пустой)
- { }, { a: 42 } (любой объект, даже пустой)
- function foo() { } (любая функция)
Равенство (equality)
В JavaScript есть два вида сравнения:
- строгое (strict) без приведения типов (
===
); - абстрактное с приведением типов.
var a = "42";
var b = 42;
a == b; // true - абстрактное, строка привелась к числу
a === b; // false - строгое
Сравнение осуществляется по некоторым простым правилам:
- Если значения (стороны сравнения) могут принимать значения
true
илиfalse
, избегайте нестрогого сравнения и используйте===
; - Если в сравнении участвуют специфические значения (
0
,""
,[]
— пустой массив), избегайте нестрогого сравнения. - В остальных случаях можно использовать
==
. Это безопасно и во многих случаях делает код более читаемым.
null и undefined
JavaScript (и TypeScript) имеют два специальных типа данных — null и undefined. Они предназначены для обозначения разных вещей (концепций):
undefined
— значение не инициализированоnull
— значение в данный момент недоступно
Ключевое слово let
Переменные, объявленные с помощью ключевого слова let
, имеют блочную область видимости. Это значит, что они недоступны снаружи блока {...}
Строгий режим (strict mode) и конструкция «use strict»
Строгий режим — фича стандарта ECMAScript 5. Размещая строку «use strict» в начале программы или функции, вы даете указание интерпретатору исполнять код в «строгом» контексте.
// не строгий режим
(function(){
"use strict";
// строгий режим
})();
// не строгий режим
В строгом режиме действуют более жесткие правила к конструкциям языка и выбрасывается больше исключений. Например, переменная, объявленная без ключевого слова (var
, let
, const
) в строгом режиме вызовет ошибку (в нестрогом будет создано новое свойство у глобального объекта).
function doSomething(val) {
"use strict";
x = val + 10; // ошибка x is not defined
}
function doSomething(val) {
"use strict";
let x = val + 10; // нет ошибки
}
Полифиллы и шимы (shim)
Шим — это любой фрагмент кода, который перехватывает обращение к API и добавляет уровень абстракции в приложение. Шимы существуют не только в вебе.
Полифилл — это шим для веба и браузерных API — специальный код (или плагин), который позволяет добавить некоторую функциональность в среду, которая эту функциональность по умолчанию не поддерживает (например, добавить новые функции JS в старые браузеры). Полифиллы не являются частью стандарта HTML5.
Транспилирование
Транспилирование, транспиляция — преобразование кода, написанного в новом стандарте в его эквивалент в старом стиле (ES6 в ES5).
Разница между ES5 и ES6
- ECMAScript 5 (ES5) — 5-е издание ECMAScript, стандартизированное в 2009 году. Поддерживается современными браузерами практически полностью.
- ECMAScript 6 (ECMAScript 2016, ES6) — 6-е издание ECMAScript, стандартизированное в 2015 году. Частично поддерживается большинством современных браузеров.
Несколько ключевых отличий двух стандартов:
- Стрелочные функции и интерполяция в строках.
// В новом стандарте можно сделать так:
const greetings = (name) => {
return `hello ${name}`;
}
// и даже так:
const greetings = name => `hello ${name}`
- Ключевое слово
const
.Константы в JavaScript отличаются от констант в других языках программирования. Они сохраняют неизменной только ссылку на значение. Таким образом, вы можете добавлять, удалять и изменять свойства объявленного константным объекта, но не можете перезаписать текущую переменную, в которой лежит этот объект.
const NAMES = [];
NAMES.push("Jim");
console.log(NAMES.length === 1); // true
NAMES = ["Steve", "John"]; // error
- Блочная видимость.Переменные, объявленные с помощью новых ключевых слов
let
иconst
имеют блочную область видимости, то есть недоступны за пределами{}
-блоков. Кроме того, они не поднимаются, какvar
-переменные. - Параметры по умолчанию.Теперь функцию можно инициализировать с дефолтным значением параметров. Оно будет использовано, если параметр не будет передан при вызове.
function multiply (a, b = 2) {
return a * b;
}
multiply(5); // 10
- Классы и наследование.Новый стандарт ввел в язык поддержку привычного синтаксиса классов (
class
), конструкторы (constructor
) и ключевое словоextend
для оформления наследования. - Оператор for-of для перебора итерируемых объектов в цикле.
spread
-оператор, который удобно использовать для слияния объектов и еще во многих случаях.
const obj1 = { a: 1, b: 2 }
const obj2 = { a: 2, c: 3, d: 4}
const obj3 = {...obj1, ...obj2}
- Обещания (Promises).Механизм для обработки результатов и ошибок асинхронных операций. По сути, это то же самое, что и коллбэки, но гораздо удобнее. Например, промисы можно чейнить (объединять в цепочки).
const isGreater = (a, b) => {
return new Promise ((resolve, reject) => {
if(a > b) {
resolve(true)
} else {
reject(false)
}
})
}
isGreater(1, 2)
.then(result => {
console.log('greater')
})
.catch(result => {
console.log('smaller')
})
- Модули. Способ разбития кода на отдельные модули, которые можно импортировать при необходимости.
import myModule from './myModule';
- Синтаксис экспорта позволяет выделить функциональность модуля:
const myModule = {
x: 1,
y: () => {
console.log('This is ES5')
}
}
export default myModule;
Примитивные значения
Является ли число целым (integer)?
Очень простой способ проверить, имеет ли число дробную часть — разделить его на единицу и проверить остаток.
function isInt(num) {
return num % 1 === 0;
}
console.log(isInt(4)); // true
console.log(isInt(12.2)); // false
console.log(isInt(0.3)); // false
Почему 0.1 + 0.2 === 0.3
— это false
?
Действительно, в JavaScript 0.1 + 0.2
на самом деле равно 0.30000000000000004. Дело в том, что все числа в языке (даже целые) представлены в формате с плавающей запятой (float). В двоичной системе счисления эти числа — бесконечные дроби. Для их хранения выделяется ограниченный объем памяти, поэтому возникают подобные неточности.
Рекурсивная функция, возвращающая двоичное представление числа
Например, получив на вход число 4, эта функция должна вернуть 100.
decimalToBinary(3); // 11
decimalToBinary(8); // 1000
decimalToBinary(1000); // 1111101000
function decimalToBinary(digit) {
// последовательно получаем каждый разряд двоичного числа
if(digit >= 1) {
// если число не делится на 2 без остатка,
// прибавляем к результату справа единицу (младший разряд)
// если делится, прибавляем 0
// делим число на 2 и продолжаем рекурсию
if (digit % 2) {
return decimalToBinary((digit - 1) / 2) + 1;
} else {
// Recursively return proceeding binary digits
return decimalToBinary(digit / 2) + 0;
}
} else {
// выход из рекурсии, если число меньше 1
return '';
}
}
Является ли число степенью двойки?
Обратите внимание, что 0 не является степенью двойки.
Решение очень простое, основано на побитовом умножении (И, &
). Этот оператор ставит 1 на бит результата, для которого соответствующие биты операндов равны 1.
Возьмем для примера 4 & 3
. Двоичное представление четверки — 100, тройки — 011. Ни в одном бите операнды не совпадают, поэтому результат будет 000.
Другой пример: 5 & 4
. В двоичном виде это 101 & 100 = 100
.
Суть решения в том, что любая степень двойки — это единственная единица и нули (2 -10, 4 — 100, 8 — 1000). Если вычесть из него единицу, полученное число будет состоять из одних единиц (1 — 1, 3 — 11, 7 — 111). То есть у самого числа (степень двойки) и этого же числа, уменьшенного на 1 все биты разные, значит, побитовое умножение в результате даст 0.
isPowerOfTwo(4); // true
isPowerOfTwo(64); // true
isPowerOfTwo(1); // true
isPowerOfTwo(0); // false
isPowerOfTwo(-1); // false
function isPowerOfTwo(number) {
return number & (number - 1) === 0;
}
Развернуть все слова в полученной строке
Решим задачу с помощью одной простой функции в два этапа: сначала развернем все предложение целиком, затем вернем исходный порядок слов.
let string = "Welcome to this Javascript Guide!";
// развернуть все предложение целиком
// вывод: !ediuG tpircsavaJ siht ot emocleW
let reverseEntireSentence = reverseBySeparator(string, "");
// сохранить исходный порядок слов
// вывод: emocleW ot siht tpircsavaJ !ediuG
let reverseEachWord = reverseBySeparator(reverseEntireSentence, " ");
function reverseBySeparator(string, separator) {
return string.split(separator).reverse().join(separator);
}
Строки-анаграммы
Определить, являются ли две строки анаграммами друг друга.
let firstWord = "Mary";
let secondWord = "Army";
isAnagram(firstWord, secondWord); // true
function isAnagram(first, second) {
// сначала приводим обе строки к нижнему регистру
let a = first.toLowerCase();
let b = second.toLowerCase();
// разбиваем строку по символам, сортируем их и снова объединяем в строку
// результаты сравниваем
a = a.split("").sort().join("");
b = b.split("").sort().join("");
return a === b;
}
Строки-палиндромы
Палиндром — это слово, фраза, число или другая последовательность символов, которая читается одинаково слева направо и справа налево. Важно учитывать, что в строке могут быть пробелы и символы в разном регистре.
isPalindrome("racecar"); // true
isPalindrome("race Car"); // true
function isPalindrome(word) {
// убрать все пробельные символы, привести к нижнему регистру
let lettersOnly = word.toLowerCase().replace(/s/g, "");
// сравнить с перевернутой версией
return lettersOnly === lettersOnly.split("").reverse().join("");
}
А вот этот вариант работает в 25 раз быстрее (если, конечно, вы сможете в нем разобраться):
function isPalindrome(s,i) {
return (i=i||0)<0||i>=s.length>>1||s[i]==s[s.length-1-i]&&isPalindrome(s,++i);
}
Изоморфные строки
Изоморфными называются строки, между символами которых можно установить однозначное соответствие. Например, paper
и title
изоморфны (p = t
, a = i
, e = l
, r = e
). Количество и порядок символов при этом необходимо учитывать.
- egg и sad — неизоморфны,
- dgg и add — изоморфны.
isIsomorphic("egg", 'add'); // true
isIsomorphic("paper", 'title'); // true
isIsomorphic("kick", 'side'); // false
function isIsomorphic(firstString, secondString) {
// проверка длины строк
if (firstString.length !== secondString.length) return false
let letterMap = {};
for (let i = 0; i < firstString.length; i++) {
let letterA = firstString[i],
letterB = secondString[i];
// если такой буквы еще не было, сохранить ее в объекте
// и поставить в соответствие с соответствующей буквой второго слова
if (letterMap[letterA] === undefined) {
letterMap[letterA] = letterB;
} else if (letterMap[letterA] !== letterB) {
// если соответствие для буквы уже установлено
// и буква второго слова не соответствует
// то строки не изоморфны
return false;
}
}
return true;
}
Объекты и массивы
Объекты
Объекты — это составные структуры. Для них можно определить именованные свойства, в каждом из которых может содержаться значение любого типа.
let obj = {
a: "hello world", // свойство a со значением "hello world"
b: 42,
c: true
};
obj.a; // "hello world", получение через точку (doted-notation)
obj.b; // 42
obj.c; // true
obj["a"]; // "hello world", получение через скобки (bracket-notation)
obj["b"]; // 42
obj["c"]; // true
Скобочная нотация также полезна, если вы хотите получить доступ к свойству, имя которого хранится в переменной:
let obj = {
a: "hello world",
b: 42
};
let b = "a";
obj[b]; // "hello world"
obj["b"]; // 42
Сравнение объектов
Непримитивные значения в JavaScript (объекты) передаются по ссылке, а операторы сравнения (==
и ===
) сравнивают именно ссылки. Поэтому два разных объекта с идентичными свойствами не будут равны друг другу.
let a = [1, 2, 3];
let b = [1, 2, 3];
a == b // false
a === b // false
Есть одна маленькая хитрость, которой можно воспользоваться для сравнения простых структур. Если сравнить объект с примитивом (например, строкой), он будет приведет к строковому представлению. Для массива, например, строковое представление — это строка со списком элементов, разделенных запятыми. Благодаря этому можно сделать так:
let a = [1, 2, 3];
let b = [1, 2, 3];
let c = "1,2,3";
a == c // true
a.toString() == b.toString() // true
Однако объекты, не являющиеся массивами, многоуровневые массивы, и объекты со сложными значениями свойств (DOM-элементы) таким образом сравнить не удастся.
Вместо приведения к строке также можно использовать сериализацию (JSON.stringify(obj)
), но этот способ тоже работает не во всех случаях.
Для глубокого сравнения нужно использовать специальные библиотеки, например, deep-equal, или рекурсивный алгоритм.
Вот здесь можно увидеть реализацию более академичного способа сравнения объектов.
Массивы
Массивы — это объекты, которые хранят значения не в именованных свойствах, а в нумерованных.
let arr = [
"hello world",
42,
true
];
arr[0]; // "hello world"
arr[1]; // 42
arr[2]; // true
arr.length; // 3
typeof arr; // "object"
Как очистить массив?
Способ 1. Присвоить переменной новый пустой массив:
let arr = [1, 2, 3];
arr = [];
Этот способ можно использовать, если ваш код никак не ссылается на оригинальный массив, так как при этом создается совершенно новый объект. Если в какой-то переменной есть ссылка на arr, то она не изменится.
let arrayList = ['a', 'b', 'c', 'd', 'e', 'f'];
let anotherArrayList = arrayList;
arrayList = [];
console.log(anotherArrayList); // ['a', 'b', 'c', 'd', 'e', 'f']
Способ 2. Обнулить длину массива
let arr = [1, 2, 3];
arr.length = 0;
Существующий массив очистится, так же как и все ссылки на него.
let arrayList = ['a', 'b', 'c', 'd', 'e', 'f'];
let anotherArrayList = arrayList;
arrayList.length = 0;
console.log(anotherArrayList); // []
Способ 3. Вырезать лишние элементы
let arr = [1, 2, 3];
arr.splice(0, arr.length);
Работает так же, как предыдущий способ:
let arrayList = ['a', 'b', 'c', 'd', 'e', 'f'];
let anotherArrayList = arrayList;
arrayList.splice(0, arrayList.length);
console.log(anotherArrayList); // []
Способ 4. Удалять элементы по одному
let arr = [1, 2, 3];
while(arr.length) {
arr.pop();
}
Довольно громоздко, но может быть полезно, если вы хотите перед удалением что-нибудь еще сделать с элементами.
Является ли объект массивом?
Лучший способ узнать, является ли объект инстансом определенного класса, — использовать метод Object.prototype.toString()
.
let arr = [1, 2, 3];
let obj = {'a': 1, 'b': 2};
let str = "hello";
let foo = function() {};
console.log(Object.prototype.toString.call(arr)); // [object Array]
console.log(Object.prototype.toString.call(obj)); // [object Object]
console.log(Object.prototype.toString.call(str)); // [object String]
console.log(Object.prototype.toString.call(foo)); // [object Function]
Таким образом, проверить, является ли полученное значение массивом можно с помощью конструкции:
function checkArray(value) {
if(Object.prototype.toString.call(value) === '[object Array]') {
console.log('Array!');
} else {
console.log('Not array');
}
}
В jQuery есть специальный метод $.isArray(value)
, который под капотом использует ту же самую проверку.
Современные браузеры (Chrome 5, Firefox 4.0, IE 9, Opera 10.5 and Safari 5) поддерживают метод Array.isArray(value)
.
Зачем вообще проверять, является ли значение массивом? Это очень полезно для перегрузки методов в зависимости от полученных параметров. Например, вы можете работать в одном и том же методе и с отдельной строкой, и с массивом строк. В каждом конкретном случае проверка на тип параметра может быть разной. Например, в приведенном примере проще будет воспользоваться оператором typeof
:
function foo(param) {
if(typeof param === 'string') {}
else {}
}
Но проверка на массив тоже может потребоваться, ведь в функцию foo может быть передан, например, обычный объект, с которым она не умеет работать.
В массиве чисел найти максимальную разницу между двумя элементами, причем большее число должно обязательно стоять после меньшего
Обязательно разберитесь в условии прежде чем приступать к решению.
Если у нас есть массив:
let array = [7, 8, 4, 9, 9, 15, 3, 1, 10];
то в ответе ожидается значение 11 (15 — 5 = 11), но не 14 (15 — 1 = 14), так как большее число должно находиться после меньшего.
Решение выглядит так:
findLargestDifference(array);
function findLargestDifference(array) {
// если в массиве всего один элемент, возвращаем -1
if (array.length <= 1) return -1;
// в currentMin сохраняем текущее минимальное значение
let currentMin = array[0];
let currentMaxDifference = 0;
// перебираем массив и сохраняем максимальную разницу в currentMaxDifference
// параллельно отслеживаем минимальный элемент
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 negative or 0, there is no largest difference
if (currentMaxDifference <= 0) return -1;
return currentMaxDifference;
}
Если алгоритм не очень понятен, обязательно разберитесь с ним на бумаге. Важно понимать, что мы не потеряем наибольшую разницу, обновляя минимальное значение, так как сравнивать его можно только со следующими большими числами.
Известно, что в неотсортированном массиве содержится (n-1)
из n
последовательных чисел (границы этого диапазона известны). Найдите пропущенное число за время O(n)
Тут важно разобраться в условии задачи. Если что-то непонятно, не стесняйтесь спрашивать.
У вас есть диапазон чисел от num1
до num2
включительно (обе границы известны). Длина диапазона — n
.
Также есть массив длины n-1
, в котором содержатся все числа из диапазона, кроме одного. Вам нужно найти это единственное пропущенное число.
Так как лишних чисел в массиве нет, недостающее можно найти, подсчитав реальную и полную суммы элементов.
// ожидаемый ответ функции - 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) {
// находим сумму всех элементов массива
let sumOfIntegers = 0;
for (var i = 0; i < arrayOfIntegers.length; i++) {
sumOfIntegers += arrayOfIntegers[i];
}
// Рассчитываем сумму всех чисел в заданном диапазоне
// используем формулу Гаусса для нахождения суммы всех чисел от 1 до заданного
// n * (n+1) : 2
let upperLimitSum = (upperBound * (upperBound + 1)) / 2;
let lowerLimitSum = (lowerBound * (lowerBound - 1)) / 2;
let theoreticalSum = upperLimitSum - lowerLimitSum;
return theoreticalSum - sumOfIntegers;
}
Время работы функции составляет O(n) так как каждый элемент перебирается всего 1 раз.
Удалить из массива повторяющиеся значения, вернуть только уникальные элементы
Эту задачу очень просто решить, используя возможности стандарта ES6 (сеты — коллекции с уникальными элементами):
let array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];
Array.from(new Set(array)); // [1, 2, 3, 5, 9, 8]
Но и на ES5 ее вполне можно решить (и даже нужно!). Для этого используем обычный объект — и устанавливаем ему свойства с именами, равными элементам массива.
let array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];
uniqueArray(array); // [1, 2, 3, 5, 9, 8]
function uniqueArray(array) {
let hashmap = {};
let unique = [];
for(var i = 0; i < array.length; i++) {
// если в объекта еще нет ключа, равного значению элемента, добавляем
if(!hashmap.hasOwnProperty(array[i])) {
hashmap[array[i]] = 1;
unique.push(array[i]);
}
}
return unique;
}
Реализуйте добавление в очередь и удаление из очереди с помощью двух стеков
Очереди элементов работают по принципу первый пришел — первый ушел.
Если мы добавляем элементы очереди в массив, чтобы получить самый первый, нужно воспользоваться методом unshift
, но это довольно тяжелая операция, так как она сдвигает индексы всех оставшихся элементов массива.
В то же время существует более легкий метод pop
, который берет последний элемент массива и не меняет порядок индексации.
Если у нас есть два массива, можно сделать так:
var inputStack = []; // первый стек
var outputStack = []; // второй стек
// добавление в очередь
// просто добавляем элемент в первый стек
function enqueue(stackInput, item) {
return stackInput.push(item);
}
// удаление из очереди
function dequeue(stackInput, stackOutput) {
// развернем стек входящих элементов (input)
// в output-стеке все элементы окажутся в обратном порядке
// первый элемент в input-стеке (первый пришедший) станет последним в output-стеке
// так его проще будет получить, не нарушая нумерацию элементов
if (stackOutput.length <= 0) {
while(stackInput.length > 0) {
let elementToOutput = stackInput.pop(); // последний из входящих
stackOutput.push(elementToOutput);
}
}
return stackOutput.pop(); // вернуть последний элемент из output-стека
}
В stackInput
элементы добавляются как в обычную очередь. Если нужно получить первый элемент, мы переворачиваем исходную очередь, там что первый элемент в stackInput становится последним в stackOutput. Забрать последний элемент из stackOutput
(который, на самом деле, первый в очереди), можно с помощью метода pop
.
Обратите внимание, пока в stackOutput
есть хоть один элемент, мы ничего не переносим из исходной очереди, чтобы не нарушать порядок. Элементы там могут накапливаться и дальше. Когда output-стек обнулится, мы вновь скопируем в него накопившиеся элементы.
Больше методов массивов в JS вы можете найти здесь.
Найти пересечение массивов
Пересечение — это набор элементов, которые присутствуют в обоих массивах. При этом необходимо отбирать только уникальные элементы.
let firstArray = [2, 2, 4, 1];
let secondArray = [1, 2, 0, 2];
intersection(firstArray, secondArray); // [2, 1]
function intersection(firstArray, secondArray) {
let hashmap = {};
let intersectionArray = [];
firstArray.forEach(function(element) {
hashmap[element] = 1;
});
secondArray.forEach(function(element) {
if (hashmap[element] === 1) {
intersectionArray.push(element);
hashmap[element]++;
}
});
return intersectionArray;
}
Сначала создаем хеш, ключами которого являются значения первого массива. Операция поиска по ключу в хеше имеет сложность O(1).
Затем перебираем элементы второго массива и проверяем, есть ли они в первом.
Общая сложность алгоритма — O(n).
В неотсортированном массиве целых чисел найти наибольшее произведение любых трех элементов
Помните, что максимальным необязательно окажется произведение трех самых больших чисел в массиве. Если минимальные элементы отрицательны, но велики по модулю, возможно искомым окажется произведение min1 * min2 * max1
(двум самых маленьких и одного самого большого).
let unsortedArray = [-10, 7, 29, 30, 5, -10, -70];
computeProduct(unsortedArray); // 21000 (-70 * -10 * 30)
function sortIntegers(a, b) {
return a - b;
}
function computeProduct(unsorted) {
// сортируем массив по возрастанию
let sortedArray = unsorted.sort(sortIntegers),
product1 = 1, // max1 * max2 * max3
product2 = 1, // min1 * min2 * max1
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;
}
Рекурсивный бинарный поиск
Вкратце: бинарный (двоичный) поиск делит отсортированный массив на половины. Подробнее — в Википедии.
function recursiveBinarySearch(array, value, leftPosition, rightPosition) {
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);
}
}
Сбалансированность скобок
let expression = "{{}}{}{}"
let expressionFalse = "{}{{}";
isBalanced(expression); // true
isBalanced(expressionFalse); // false
isBalanced(""); // true
function isBalanced(expression) {
let checkString = expression;
let stack = [];
// если строка пуста, то считаем скобки сбалансированными
if (checkString.length <= 0) return true;
for (let i = 0; i < checkString.length; i++) {
if(checkString[i] === '{') {
stack.push(checkString[i]);
} else if (checkString[i] === '}') {
// Pop on an empty array is undefined
if (stack.length > 0) {
stack.pop();
} else {
return false;
}
}
}
// If the array is not empty, it is not balanced
if (stack.pop()) return false;
return true;
}
Функции и классы
Функция обратного вызова (callback) с простым примером
Коллбэк — это функция, которая передается в другую функцию как аргумент и выполняется после того, как закончатся какие-то другие операции. В примере ниже коллбэк логирует в консоль.
function modifyArray(arr, callback) {
// некоторые операции с массивом arr
arr.push(100);
// после того, как операции закончены, выполняется коллбэк
callback();
}
let arr = [1, 2, 3, 4, 5];
modifyArray(arr, function() {
console.log("массив модифицирован", arr);
});
Область видимости (scope)
Каждая функция в JS имеет собственную область видимости (scope). Это коллекция переменных и правила доступа к ним. Если переменная объявлена внутри функции (в ее скоупе), то доступ к ней может получить только код внутри этой функции.
Области видимости могут быть вложены друг в друга, при этом все внутренние скоупы имеют доступ к переменным из внешних.
Замыкания (closures)
В C и большинстве других распространенных языков после возврата функции (оператор return
или просто окончание работы) все локальные переменные становятся недоступными, так как фрейм стека уничтожается. В JavaScript они остаются в некотором смысле доступными.
Замыкание — это фрейм стека, который выделяется, когда функция начинает свое работу, и не освобождается после ее возврата (как если бы он был выделен в куче, а не в стеке!). Вы можете думать о переменной одновременно как об указателе на функцию, так и как о скрытом указателе на замыкание.
Говоря простыми словами, замыкание — это функция, созданная и возвращенная из другой функции, которая имеет доступ к родительскому скоупу.
Счетчик с помощью замыкания (closure)
Если мы создаем счетчик, то, скорее всего, не хотим, чтобы внешний код мог повлиять на накопленное значение. Значит, его нужно каким-то образом защитить. Замыкания отлично справляются с этой задачей.
function counter() {
let _counter = 0; // переменная недоступна извне функции
// вернем объект с полезными методами счетчика
// которые смогут увеличивать приватную переменную _counter
// и возвращать текущее значение
return {
add: function(increment) { _counter += increment; },
retrieve: function() { return 'The counter is currently at: ' + _counter; }
}
}
// ошибка: нельзя получить доступ к переменной внутри замыкания
// _counter;
// создаем и увеличиваем счетчик
let c = counter();
c.add(5);
c.add(9);
// получаем текущее значение
c.retrieve(); // => The counter is currently at: 14
Каррирование (закрепление аргумента)
Каррирование — преобразование функции от многих аргументов в набор функций, каждая из которых является функцией от одного аргумента. (с) Википедия.
Пример задачи. Напишите функцию createBase, которая будет фиксировать первое слагаемое и добавлять к нему любое число:
var addSix = createBase(6);
addSix(10); // 16
addSix(21); // 27
Решим задачу с помощью замыкания:
function createBase(baseNumber) {
return function(N) {
// значение baseNumber сохранится в замыкании функции
// оно будет "зафиксировано"
return baseNumber + N;
}
}
var addSix = createBase(6);
addSix(10);
addSix(21);
Вот еще одна задачка на ту же тему. Нужно написать функцию, которая будет перемножать полученные аргументы, но с необычным синтаксисом:
console.log(mul(2)(3)(4)); // output : 24
Тут все то же самое, просто мы не фиксируем первый (или первый и второй) множители в отдельной переменной.
function mul (x) {
return function (y) {
return function (z) {
return x * y * z;
};
};
}
Тут нужно понимать две основные концепции JS:
- Функция является объектом первого класса, то есть ее можно свободно возвращать из другой функции или сохранять в переменной как обычное значение.
- Замыкания, с помощью которых при необходимости можно зафиксировать первый параметр.
IIFE (Immediately Invoked Function Expression) и паттерн Модуль
IIFE, или немедленно выполняемое функциональное выражение, — это объявление функции с ее немедленным выполнением.
(function IIFE(){
console.log( "Hello!" );
})();
// "Hello!"
Такой синтаксис позволяет избежать загрязнения глобального пространства имен, ведь все необходимые переменные можно спрятать в замыкании.
С помощью IIFE в JavaScript реализуется паттерн проектирования Модуль — независимый от внешнего кода компонент.
Как создать по-настоящему приватный метод класса и в чем недостатки таких методов?
Создать действительно приватный метод в JS можно, только поместив его в замыкание конструктора.
var Employee = function (name, company, salary) {
this.name = name || ""; // Публичное свойство
this.company = company || ""; // Публичное свойство
this.salary = salary || 5000; // Публичное свойство
// Приватный метод
let increaseSalary = function () {
this.salary = this.salary + 1000;
};
// Публичный метод
this.dispalyIncreasedSalary = function() {
increaseSalary();
console.log(this.salary);
};
};
let emp1 = new Employee("John","Pluto",3000);
let emp2 = new Employee("Merry","Pluto",2000);
let emp3 = new Employee("Ren","Pluto",2500);
Недостатком такого способа является неизбежное дублирование. Функция increaseSalary будет создаваться для каждого экземпляра Employee, хотя в этом нет необходимости.
Паттерн Прототип, прототипное наследование
Паттерн Прототип (Шаблон Свойств) создает новые объекты, которые сразу же инициализируются значениями, скопированными из некоторого образца (прототипа). Это могут быть дефолтные значения из базы данных, например.
Этот Паттерн нечасто используется в классических языках программирования, но в JavaScript на нем полностью построена объектная модель. До ES6 даже привычного синтаксиса классов не было (сейчас это просто синтаксический сахар).
Смысл прототипного наследования заключается в том, что свойство или метод объекта, к которому происходит обращение, ищется интерпретатором сначала в самом объекте, затем в его прототипе, прототипе прототипа и так далее по цепочке.
Задача по прототипной модели
Что выведет этот код?
let Employee = {
company: 'xyz'
}
let emp1 = Object.create(Employee);
delete emp1.company
console.log(emp1.company);
Ответ: ‘xyz’. Оператор delete
удаляет только собственные свойства объекта, а свойство company
определено в прототипе.
Проверить, является ли свойство собственным можно с помощью метода emp1.hasOwnProperty('company')
.
Можно удалить свойство напрямую из прототипа: delete emp1.__proto__.company
.
Ключевое слово new
new
создает новый объект с типом object
и устанавливает его внутреннее свойство [[prototype]]
(__proto__
— равно свойству prototype
функции-конструктора). Указатель this
при этом указывает на только что созданный объект. После того как конструктор модифицирует этот объект, он возвращается.
Выглядит это примерно так:
function New(func) {
let res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
let ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return res;
}
Ключевое слово this
this всегда ссылается на объект, в контексте которого вызван метод. Этот объект определяется динамически, его можно менять. Метод, определенный в одном объекте, вполне может быть вызван в контексте другого.
function foo() {
console.log( this.bar );
}
let obj1 = {
bar: "obj1",
foo: foo
};
let obj2 = {
bar: "obj2"
};
obj1.foo(); // "obj1"
foo.call( obj2 ); // "obj2"
new foo(); // undefined
Обратите внимание, при вызове функции с new
она выступает как конструктор и возвращает пустой объект, у которого не определено свойство bar
.
Если вызвать функцию без контекста (foo()
) в строгом режиме, будет ошибка, так как this
в этом случае не определен.
Привязка контекста функции — метод bind
Метод bind()
создает новую функцию, для которой зафиксирован this
и последовательность аргументов, предшествующих аргументам при вызове новой функции.
Удобно использовать для привязки контекста или закрепления параметров.
function fullName() {
return "Hello, this is " + this.first + " " + this.last;
}
console.log(fullName()); // => Hello this is undefined undefined
// привязка контекста
var person = {first: "Foo", last: "Bar"};
console.log(fullName.bind(person)()); // => Hello this is Foo Bar
Как добавить массивам пользовательский метод?
Так как JavaScript основан на прототипах, чтобы добавить новый метод всем массивам, нужно определить его в прототипе массивов (объект Array.prototype
).
Array.prototype.average = function() {
let sum = this.reduce(function(prev, cur) { return prev + cur; });
return sum / this.length;
}
let arr = [1, 2, 3, 4, 5];
let avg = arr.average();
console.log(avg); // => 3
Браузерный JS
Всплытие событий и как его остановить
Всплытие событий — это концепция DOM-модели. Когда событие генерируется на элементе, все родительские элементы последовательно о нем оповещаются. Поэтому вы можете повесить обработчик клика на контейнер карточки и таким образом узнать о клике по вложенной кнопке.
Остановить всплытие можно с помощью метода объекта события event.stopPropagation()
. В IE < 9 у объекта события есть свойство event.cancelBubble
.
Дорогие друзья! Предлагаем вашему вниманию перевод статьи, опубликованной на DOU.ua 21 декабря 2020 года. Оригинальная версия на украинском языке доступна по ссылке.
На этот раз предлагаем ознакомиться с актуальными вопросами, которые задают на технических интервью по JavaScript. Естественно, мы говорим о широком спектре специализаций, поэтому выбирайте свое направление и готовьтесь.
Junior
Общие:
1. Какие методы HTTP-запросов вы знаете?
2. Какие версии HTTP-протокола вам известны?
3. Какие знаете коды ответа (состояния) HTTP?
4. Что такое Cross-Origin Resource Sharing? Как устранить проблемы с CORS?
5. Что такое cookie?
6. Какой максимальный размер cookie?
7. Что означает директива use strict?
8. Чем JS отличается при работе на front-end и back-end?
9. Что такое статическая и динамическая типизации?
10. Как клиент взаимодействует с сервером?
11. Что такое REST?
12. Объяснить понятие мутабельность/иммутабельность? Какие типы являются мутабельными и наоборот?
13. Как искать ошибки в коде? Используете ли вы дебаггер?
14. Каких известных людей из мира JS знаете?
JS Core
15. Какие существуют типы данных в JS?
16. Как проверить, является ли объект массивом?
17. Как проверить, является ли число конечным?
18. Как проверить, что переменная равна NaN?
19. Чем отличается поведение isNaN() и Number.isNaN()?
20. Сравните ключевые слова var, let, const.
21. Что такое область видимости?
22. Что такое деструктуризация?
23. Для чего предназначены методы setTimeout и setInterval?
24. Сравните подходы работы с асинхронным кодом: сallbacks vs promises vs async / await.
25. Можно ли записывать новые свойства / функции в прототипы стандартных классов (Array, Object и т. д.)? Почему нет? В каких случаях это делать можно? Как обезопасить себя, если нужно расширить прототип?
26. Назовите методы массивов, какие помните, и скажите, для чего они нужны.
27. Какие методы перебора массива знаете? В чем их отличие?
28. Как работают операторы присваивания / сравнения / строчные / арифметические / битовые и т. д.?
29. Опишите назначение и принципы работы с коллекциями Map и Set.
30. Что означает глубокая (deep) и поверхностная (shallow) копия объекта? Как сделать каждую из них?
Ответы на некоторые из этих вопросов вы можете найти в видео курсе JavaScript Стартовый (урок 3, урок 5, урок 10), JavaScript Базовый (урок 3, урок 13, урок 19), ECMAScript 6 (урок 6).
Функции:
31. Какая разница между декларацией функции (function declaration) и функциональным выражением (function expression)?
32. Что такое анонимная функция?
33. Расскажите о стрелочных функциях (arrow function). В чем заключаются отличия стрелочных функций от обычных?
34. Что такое и для чего используют IIFE (Immediately Invoked Function Expression)?
35. Что такое hoisting, как он работает для переменных и функций?
36. Что такое замыкание (closure) и какие сценарии его использования?
37. Как вы понимаете замыкания? Что будет выведено в консоли в этом случае?
var f = function() {
console.log(1);
}
var execute = function(f) {
setTimeout(f, 1000);
}
execute(f); // что выведет в консоль и почему
f = function() {
console.log(2);
}
38. Что такое рекурсия?
39. Что означает ключевое слово this?
40. Что такое потеря контекста, когда происходит и как ее предотвратить?
41. Методы функций bind / call / apply — зачем и в чем разница?
Ответы на некоторые из этих вопросов вы можете найти в видео курсе JavaScript Стартовый (урок 11, урок 12) и JavaScript Базовый (урок 13, урок 14).
Front-end
42. Что такое DOM?
43. Сравните атрибуты подключения скрипта async и defer в HTML-документе.
44. Какая разница между свойствами HTML-элементов innerHTML и innerText?
45. Опишите процесс всплытия (bubbling) событий в DOM.
46. Как остановить всплытие (bubbling) события?
47. Как остановить дефолтную обработку события?
48. Чему равен this в обработчике событий (event handler)?
49. Что такое LocalStorage и SessionStorage? Какой максимальный размер LocalStorage?
50. Как получить высоту блока? Его положение относительно границ документа?
51. Что такое webpack?
52. Чем отличается dev-сборник от prod?
Ответы на некоторые из этих вопросов вы можете найти в видео курсе JavaScript Базовый (урок 1, урок 6, урок 7, урок 8, урок 17) и ECMAScript 6 (урок 1).
Верстка
53. Что такое блочная модель CSS?
54. Какие способы центрирования блочного контента по горизонтали и вертикали знаете?
55. Какие подходы в верстке вам известны (float, flex, grid, etc.)?
56. Как сделать приложение responsive?
57. Какие есть принципы семантической верстки?
58. Зачем нужны префиксы для некоторых CSS-свойств (-webkit-, -moz- и т. д.)?
59. Как упростить написание кросс-браузерных стилей?
60. Практические задачи: прокомментировать и исправить пример плохого CSS или HTML.
61. Что такое CSS-препроцессоры? С какими работали? Что нового они приносят в стандартный CSS?
Ответы на некоторые из этих вопросов вы можете найти в видео курсе HTML5 & CSS3 Стартовый (урок 5, урок 6), HTML5 & CSS3 Углубленный (урок 4). Курсы Верстка сайта на CSS Grid и Верстка сайта на FlexBox CSS дадут комплексные знания и практические навыки применения технологий FlexBox и Grid.
Angular
62. Перечислите основные компоненты фреймворка (модуль, роут, директива и т .п.).
63. В чем разница между компонентом и директивой?
64. Расскажите о жизненном цикле компонента.
65. Перечислите часто используемые хуки жизненного цикла компонента и расскажите, для чего они нужны?
66. В чем разница между конструктором и ngOnInit-хуком?
67. Как защитить роут от несанкционированного доступа? Какие механизмы предоставляет для этого фреймворк?
68. Что такое Lazy loading, как и для чего используется?
69. Какое назначение RouterOutlet?
70. Как компоненты могут взаимодействовать друг с другом?
71. Как создать two-way binding свойство для компонента?
72. Какие типы форм у фреймворка? В каких случаях и что лучше использовать?
73. Какие состояния у формы и как это можно применить?
74. Зачем нужны сервисы? Как с ними работать?
75. Что такое singleton-сервисы? Каково их назначение? Способ создания?
76. Какие есть способы объявления сервисов?
77. Для чего нужны модули? Сколько их должно быть в проекте?
78. Зачем нужны общие модули (shared)?
79. Какие преимущества типизации в TypeScript?
80. Какие возможности TypeScript можно использовать для типизации (здесь имеются в виду интерфейсы, типы, enum и т. д.)?
81. Какая разница между интерфейсом и классом?
82. В чем разница между интерфейсом и абстрактным классом?
83. Какая разница между интерфейсом и типом?
84. Что такое RxJS? Как он используется во фреймворке? Какие компоненты фреймворка тесно связаны с ним?
85. Чем отличаются Observable и Promise?
86. Для чего нужны Subjects? Какие типы Subjects существуют?
87. Как сделать несколько последовательных запросов к API с помощью HTTP-сервиса и RxJS?
88. Какая разница между switchMap, concatMap, mergeMap?
89. Как можно конфигурировать Angular-приложение?
90. Зачем нужны environment-файлы? Когда их лучше не использовать?
91. В чем разница между «умным» (smart) и «глупым» (dumb) компонентами? В каких случаях применяется каждый из них?
92. В чем разница между NgForm, FormGroup и FormControl и как их применяют для построения форм?
93. Зачем нужен и как работает async pipe?
94. Как следить за развитием фреймворка? Каких известных людей, связанных с Angular, знаете / читаете?
Ответы на некоторые из этих вопросов вы можете найти в видео курсах Angular Базовый и Angular Углублённый.
React
95. Работали ли вы с классовыми компонентами? В чем их особенность?
96. Какие данные лучше хранить в состоянии компонента, а какие передавать через пропсы? Приведите пример.
97. Ознакомлены ли вы с хуками? В чем их преимущества? Приходилось ли делать свои и с какой целью?
98. Знакомы ли вы с фрагментами и порталами? Зачем они нужны?
99. Когда и для чего используют рефы?
100. Какие вы знаете методы жизненного цикла компонента?
101. В каком методе жизненного цикла компонента лучше делать запросы на сервер? Почему?
102. В каком методе жизненного цикла компонента лучше делать подписку и отписку от листенера? Почему? Зачем отписываться?
103. Был ли опыт работы с контекстом? Когда его стоит использовать?
104. В чем особенность PureComponent?
105. Работали ли вы с мемоизоваными селекторами (memoized selectors)? Для чего их используют и какой принцип работы?
106. В чем видите преимущества библиотеки React?
107. Почему библиотека React быстрая? Что такое Virtual DOM и Shadow DOM?
108. Зачем в списках ключи? Можно ли делать ключами индексы элементов массива? Когда это оправдано?
109. В чем основная идея Redux?
110. Работа со стилями в React.
111. React — это библиотека или фреймворк? Какая разница между этими двумя понятиями.
112. Можно ли использовать jQuery вместе с React? Почему да / нет?
113. Что такое codemod?
114. Приходилось ли вам настраивать проект React с нуля? С помощью каких инструментов вы это делали?
115. Перечислите все библиотеки, которые использовали в связке с React.
116. Что самое сложное вам приходилось реализовывать с помощью React?
Ответы на некоторые из этих вопросов вы можете найти в видео курсах React Базовый и React Углублённый.
Back-end
117. Что такое REPL?
118. Что такое streams в Node.js?
119. Что такое middleware?
120. Для чего используют функцию setImmediate?
121. Зачем нужен app.param() в express?
122. Что такое token based authentication?
Базы данных
123. Напишите простой запрос для вычисления трех авторов, у которых больше всего книг.
124. Напишите запрос, который выбирает последние три комментарии для конкретного пользователя для двух таблиц: комментарии и пользователи.
125. Спроектируйте простую схему базы данных для библиотеки.
126. Для чего используют SQL-оператор HAVING?
127. Зачем используют SQL-оператор LEFT JOIN?
128. Чем отличается embed- от reference-связи в MongoDB?
129. В одном проекте программисты сохраняют данные в MongoDB-коллекции комментариев, используя такие типы данных (смотрите ниже). Что плохого в этом решении?
id: ObjectID
text: string
author_id: string
created_at: Date
130. В проекте понадобилось внести изменения в структуру таблиц, добавить несколько полей и индексы. Как программисты будут делать это на продакшене?
Ответы на некоторые из этих вопросов вы можете найти в видео курсе SQL Базовый.
Инструменты
131. Каждый раз, когда вы делаете pull, почему-то случается конфликт в последней строке во всех файлах, которые вы редактировали. Что происходит?
132. Что делает команда git fetch?
133. Какой git hygiene подходы вы знаете?
134. Что такое CI / CD? Для чего это нужно?
Практические задания
135. Расскажите, какие есть способы копирования простого объекта типа obj = {a 1, b 2, c 3}
136. Напишите deep clone для объекта.
137. Назовите различные способы, как поменять местами значения двух переменных.
138. Менеджер попросил в задаче поменять статусы из «active, inactive» на «active, removed», но в коде фигурируют только цифры и непонятно, какой статус соответствует какой цифре. Как помочь будущим программистам не лезть в документацию по коду? Вопрос ставят на конкретном примере с кодом.
139. Необходимо сделать мини проект — список пользователей с формой создания / редактирования пользователя:
- Для хранения пользователей используйте Firebase (это бесплатно).
- Для стилизации используйте Bootstrap.
- Минимальный набор полей пользователя:
- имя;
- фамилия;
- электронная почта;
- телефон (в формате +380 (XX) XXX-XX-XX)
- дата рождения;
- будет плюсом — добавление аватара и возможность crop-картинки.
- Пользователи должны иметь возможность фильтрации и пагинацию.
- Проект должен содержать README-файл с шагами для запуска.
Middle
Общие
1. Расскажите о пирамиде тестирования.
2. Какие типы автоматизированных тестов выпадала возможность писать? Какие библиотеки при этом использовали? Каким инструментам отдаете предпочтение и почему?
3. Что такое unit-тесты? Какое место в пирамиде тестирования занимают unit-тесты?
4. Что такое code coverage? Обязательно 100% покрытие тестами кода?
5. Как запретить браузеру отдавать кэш на HTTP-запрос?
6. Что такое XSS (Cross-Site Scripting)?
7. Расскажите о паттернах Observer, Pub / Sub. Какая между ними разница? Приведите примеры реализации этих паттернов в известных фреймворках / библиотеках / браузерных API.
8. С какой целью может быть использован event listener события fetch self.addEventListener ( ‘fetch’, event => {})?
9. Что такое Event loop и как он работает? Расскажите о микрозадачах и макрозадачах.
JS Core
10. Какие типы данных бывают в JavaScript? Какой будет результат выполнения кода?
let firstObj = { name: ‘Hello’ };
let secondObj = firstObj;
firstObj = { name: ‘Bye’ };
console.log(secondObj.name);
11. Что такое temporal dead zone?
12. Как работает boxing / unboxing в JavaScript?
13. В чем разница между оператором in и методом hasOwnProperty?
14. Опишите, с помощью чего в JS реализуются такие ООП-парадигмы, как инкапсуляция, полиморфизм, абстракция?
15. Что такое прототип? Как работает прототипное наследование в JS? Объясните работу кода.
function Main () {}
Main.prototype = { protected: true };
const obj = new Main();
Main.prototype = { protected: false };
console.log(‘Object protection: ‘, obj.protected);
16. Какая разница между композицией и наследованием?
17. Почему не стоит использовать конструкторы типа new String?
18. Расскажите о базовом устройстве и механизме работы Event loop.
19. Что такое записи (records) и кортежи (tuples)? Чем они отличаются от обычных объектов?
20. Какие различия в поведении ES5 функции-конструктора и ES2015 класса?
21. Как реализовать паттерн «Модуль»?
22. Почему typeof null возвращает object?
23. Что такое приведение (преобразование) типов в JS?
24. Что такое явное и неявное приведение (преобразование) типов данных в JS? Как происходит преобразование типов в следующих примерах:
{}+[]+{}+[1]
!!»false» == !!»true»
[‘x’] == ‘x’
25. Что такое Garbage Collector?
26. Опишите основные принципы работы «сборщика мусора» в JS-движках (engines).
27. Опишите назначение и принципы работы с коллекциями WeakMap и WeakSet? Чем они отличаются от коллекций Map и Set соответственно?
28. Чем отличается Observable от Promise?
29. Что такое Promise? Назовите порядок выполнения then и catch в цепочке.
Promise.resolve(10)
.then(e => console.log(e)) // ??
.then(e => Promise.resolve(e))
.then(console.log) // ??
.then(e => {
if (!e) {
throw ‘Error caught’;
}
})
.catch(e => {
console.log(e); // ??
return new Error(‘New error’);
})
.then(e => {
console.log(e.message); // ??
})
.catch(e => {
console.log(e.message); // ??
});
30. Расскажите о последовательном и параллельном выполнении асинхронных функций. В чем разница между Promise.all() и Promise.allSettled()?
31. Что такое дескрипторы свойств объектов? Расскажите об их практическом применение.
32. Назовите несколько способов создания постоянного (неизменного) объекта в JavaScript.
33. Как создать свойство у объекта, которое нельзя будет изменить?
34. Зачем нужен конструктор Proxy? Приведите пример использования.
35. Что такое ArrayBuffer? В чем разница между Uint32Array и Float32Array? Каков результат выполнения кода?
const uint32Array = new Uint32Array();
Array.isArray(uint32Array);
36. Каким будет результат сравнения?
const url = “HTTPs://xyz.com/path<to>page.html”;
encodeURI(url) == encodeURIComponent(url);
37. Расскажите о генераторах и итераторах.
38. Объясните, что делает приведенный ниже код:
function * fn(num) {
for (let i = 0; i < num; i += 1) {
yield console.log(i);
}
}
const loop = fn(5);
loop.next();
loop.next();
39. Расскажите о типе данных Symbol и его практическом применении. Как перевести число с 10-разрядной системы в 16 (2,8) разрядную систему счисления?
Ответы на некоторые из этих вопросов вы можете найти в видео курсе JavaScript Стартовый (урок 3, урок 4, урок 13, урок 14) и JavaScript Базовый (урок 18, урок 19), ECMAScript 6 (урок 6).
Функции
40. Объясните, что означает currying. Приведите пример использования на практике.
41. Приведите пример функции с мемоизацией. Когда следует применять эту технику?
42. Что такое чейнинг функций? Напишите пример с использованием этого подхода.
43. В чем разница между function и arrow function? Каким будет результат выполнения кода?
const pluckDeep = key => obj => key.split(‘.’).reduce((accum, key) => accum[key], obj)
Видео курсы по схожей тематике:
const compose = (…fns) => res => fns.reduce((accum, next) => next(accum), res)
const unfold = (f, seed) => {
const go = (f, seed, acc) => {
const res = f(seed)
return res ? go(f, res[1], acc.concat([res[0]])) : acc
}
return go(f, seed, [])
}
Front-end
44. В чем принципиальная разница между событиями mouseleave и mouseout?
45. В каком порядке обрабатываются пользовательские события в DOM (click, mouseover и т .д.)? FIFO или LIFO?
46. Что такое Event bubbling и Event capturing?
47. Сравните методы объекта event stopPropagation и stopImmediateProparation.
48. Какие есть подходы оптимизации производительности веб-страницы?
49. Как реализован механизм same-origin policy в браузере? На какие браузерные API он распространяется?
50. Назовите способы хранения данных в браузере. Сравните их.
51. Web worker`ы. Опишите особенности передачи данных между worker`амы и основным потоком, между разделенными worker`амы.
51. Что такое Transferable-объекты?
52. Расскажите о способах оптимизации выполнения ресурсоемких операций JS для улучшения производительности рендеринга контента на странице.
53. Почему ResizeObserver вызывает события изменения размера до воспроизведения элемента, а не после?
54. Расскажите, как вы понимаете Web Accessibility?
55. Опишите алгоритм создания функционала, который обеспечивает чтение содержимого .txt файла при перетаскивании его из файловой системы в окно браузера.
56. Что такое Virtual DOM?
Ответы на некоторые из этих вопросов вы можете найти в видео курсе HTML5 & CSS3 Углубленный (урок 3), JavaScript Базовый (урок 1, урок 2, урок 3).
Верстка
57. Объясните разницу между единицами измерения px, em, rem.
58. Для чего нужны CSS-переменные? Приведите несколько примеров использования.
59. Что произойдет при добавлении следующего селектора?
* {Box-sizing: border-box; }
60. Как адаптировать страницу для печати?
61. Опишите особенности кастомизации стилей стандартных элементов форм.
62. Что такое progressive рендеринг? Какие подходы используются?
63. Назовите несколько способов реализации lazy-loading медиаресурсов на странице.
64. Назовите популярные шаблонизаторы для фронтенд-разработки. Опишите особенности их использования.
65. Назовите популярные CSS-методологии и их различия.
66. Как работает CSS Grid?
67. Какие форматы изображений поддерживают анимацию?
68. Как отследить прогресс / окончание CSS @keyframes анимаций или плавных переходов, реализованных с помощью transition, в JS?
69. Какие CSS-свойства могут быть обработаны непосредственно через GPU? Что такое композитные слои и почему большое их количество может привести к аварийному завершению работы браузера на мобильных устройствах?
70. Как переиспользовать Инлайн SVG-элементы на странице?
71. Опишите способы оптимизации SVG-файлов.
72. Как реализовать иконочный шрифт из определенного набора SVG-файлов?
73. Что такое ложное жирное или ложное курсивное (Faux) начертание шрифтов?
74. Что такое #shadow-root в инспекторе HTML-страницы?
75. Зачем нужны Custom Elements?
76. Почему удаление лишних символов пробелов / символов переноса в HTML не отражается на конечной производительности загрузки страницы?
77. Что такое контекст отображения canvas? Какие существуют типы контекста для рендеринга двумерной и трехмерной графики?
Ответы на некоторые из этих вопросов вы можете найти в видео курсе HTML5 & CSS3 Углубленный.
Angular
78. Как работает Dependency injection? Зачем это нужно? Расскажите об использовании кастомных инжекторов.
79. Что такое zone.js? Для чего Angular использует зоны? С какой целью можно использовать NgZone-сервис?
80. Как работает Change detection? Как можно оптимизировать компонент с помощью схем Change detection? Какие еще есть приемы для оптимизации рендеринга (связанные с Change detection)?
81. Как выполнить конфигурацию HTTP-сервиса? Зачем она нужна? Обработка HTTP-ошибок?
82. Какие есть подходы к организации работы с данными?
83. Как подготовить сборник к деплою?
84. Что такое NgRx? Когда стоит использовать?
85. В каких случаях лучше использовать Renderer-сервис вместо нативных методов? И наоборот?
86. Как работают и для чего нужны резолверы? Как получить данные, загруженные резолверами?
87. Как работают и зачем нужны динамические компоненты? Приведите примеры их целесообразного использования.
88. Какая разница между @ViewChild и @ContentChild?
89. Что делает код и как иначе можно связать класс компонента с переменной?
@HostBinding ( ‘class.valid’) isValid;
90. Как можно кэшировать данные, используя сервисы или RxJS?
91. Что такое асинхронная валидация форм? Когда применяется и как реализуется?
92. Зачем нужна forRoot-функция модуля?
93. Какая разница между декларированием и экспортом компонента из модуля?
94. Почему плохо «провайдить» сервис с shared-модуля в lazy-loaded модуль? (Вопрос о scope модулей.)
95. Что такое :: ng-deep и для чего используется?
96. Какие тесты можно запустить для Angular-программы? Какие инструменты используют для тестирования Angular-программы?
97. Как протестировать API-сервис?
Ответы на некоторые из этих вопросов вы можете найти в видео курсах Angular Базовый и Angular Углублённый.
React
98. Что такое JSX? Что лежит в его основе?
99. Как работает алгоритм Virtual DOM?
100. Для чего нужно свойство key во время рендеринга списков?
101. В чем разница между функциональными и классовыми компонентами?
102. Зачем и когда нужно передавать props в super() при использовании классовых компонентов?
103. Почему нужно использовать setState() для обновления внутреннего состояния компонента?
104. В чем заключается принцип «подъема состояния»?
105. Какие библиотеки менеджмента состояния React-приложения вы знаете? Зачем они нужны?
106. Когда следует использовать Redux? Какие есть альтернативы?
107. Redux vs Mobx?
108. Расскажите о базовом принципе работы React Hooks.
109. В чем разница между createRef и useRef?
110. Когда следует использовать React refs? Когда не стоит?
111. Какие недостатки библиотеки React видите?
112. Какие паттерны используете вместе с React?
113. Как относитесь к типизации вместе с React?
114. Как построить хорошую архитектуру React-проекта?
115. Оптимизация React-приложений? Как измерить производительность программы?
116. Можно ли приложение на React встроить в другое приложение на React?
Ответы на некоторые из этих вопросов вы можете найти в видео курсах React Базовый и React Углублённый.
Back-end
117. Почему Node.js однопоточный, а не многопоточный?
118. Что такое event driven development?
119. Сравните fork() и spawn() методы.
120. Расскажите о Node.js фреймворках, которые использовали. Какая между ними разница?
121. Опишите словам код ендпоинта, который должен сохранить с клиента файл размером 4 гигабайта и положить его на S3 или другой CDN.
122. Что такое микросервисы, зачем их используют?
123. В каких случаях вы бы выбрали монолит, а в каких — микросервисы?
124. Как понять, что приложение в определенный момент работает исправно?
125. Как понять, что приложение за последние три дня работал исправно?
126. Как происходит проверка правильности пароля при использовании bcrypt?
127. Что такое JWT?
128. Джуниор прислал код на ревью. Что здесь не так? Как исправить?
router.post ( ‘/ users’, async (req, res, next) => {
const user = await db.createUser (req);
if (user) {
return res.json (users);
}
res.json ({error: «can not create user»})
})
Базы данных
129. Что такое Redis и для чего его используют?
130. Какие базы данных использовали? Какая разница между SQL и NoSQL?
131. Для двух таблиц — комментарии и пользователи — напишите запрос, который выбирает последние три комментария для каждого пользователя.
132. Я как заказчик прошу выбрать вас базу данных для нового проекта. Ваши действия?
Инструменты и другое
133. Для чего нужен package-lock.json?
134. В чем разница между npm install и npm ci?
135. Для чего нужны бандлеры?
136. Расскажите о модульном подключении скриптов. Приведите пример использования загрузчиков / бандлеров модулей.
137. Чем различаются git merge и git rebase?
138. Что такое staging area в git?
139. Опишите процесс code review. Назовите основные правила, способы разрешения конфликтов и споров во время его проведения.
Практические задания
140. Напишите функцию Sleep (ms), которая останавливает выполнение async-функции на заданный промежуток времени.
141. Реализуйте один из методов массива (например, splice).
142. Напишите функцию с RegExp для нахождения всех HTML-ссылок в строке.
143. Реализуйте функцию, которая исполнит callback для всех элементов определенной ветви DOM-дерева.
144. Реализуйте таблицу с виртуальным скролом.
145. Реализуйте функцию преобразования URL query строки в JSON.
const inData = «user.name.firstname=Bob&user.name.lastname=Smith&user.favoritecolor=Light%20Blue»;
function queryObjectify(arg) {
// ??
}
queryObjectify(inData)
/* Результатом виконання для вхідного рядка, повинен бути наступний об’єкт
{
‘user’: {
‘name’: {
‘firstname’: ‘Bob’,
‘lastname’: ‘Smith’
},
‘favoritecolor’: ‘Light Blue’
}
};
*/
146. Реализуйте функцию нахождения пересечения двух массивов.
const first = [1, 2, 3, 4];
const second = [3, 4, 5, 6];
function intersection (a, b) {
// ??
}
intersection(first, second) // -> [3, 4]
147. Реализуйте функцию / класс для генерации HTML.
const HTMLConstruct = {};
HTMLConstruct.span(‘foo’); // -> <span>foo</span>
HTMLConstruct.div.span(‘bar’); // -> <div><span>bar</span></div>
HTMLConstruct.div.p(
HTMLConstruct.span(‘bar’),
HTMLConstruct.div.span(‘baz’)
); // -> <div><p><span>bar</span><span>baz</span></p></div>
148. Если есть проект с ограниченными сроками и некритичной производительностью, чем будете руководствоваться при выборе библиотек, подходов? Или все же будете обращать внимание на производительность? Или наоборот: сроки нелимитированные, производительность важна. Ваши действия?
Senior
Общие
1. Расскажите о функциональном программировании.
2. Что такое TDD (Test Driven Development) / BDD (Behaver Driven Development)?
3. Расскажите подробно о работе HTTPS.
4. Какой стек технологий можно выбрать для реализации клона какого-нибудь известного проекту и почему?
5. Имеется проект на старых технологиях, необходимо в него вносить изменения. Как это сделать лучше всего?
Бесплатные вебинары по схожей тематике:
6. Если у кандидата есть опыт работы с несколькими фреймворками: какой будете использовать для следующего проекта? Какие факторы будут влиять на выбор?
7. Что такое V8 Engine?
JS Core
8. Реализация паттерна Class Free OOP (HTTPs://observablehq.com/@bratter/class-free-oop).
9. Патерн async disposer (HTTPs://advancedweb.hu/what-is-the-async-disposer-pattern-in-javascript).
10. использование регулярных выражений. Когда приемлемо / неприемлемо? Как они работают? Как можно сделать читабельный код?
Front-end
11. Как браузер определяет, можем ли мы общаться между вкладками?
12. Что такое Content Security Policy?
13. Как избежать загрузки кэшированных файлов скриптов и стилей?
14. Что такое requestAnimationFrame?
15. Расскажите о микросервисной архитектуре Front-end App.
16. Что такое Shadow DOM?
17. Сравните nextElementSibling и nextSibling.
18. Какие знаете метрики веб-сайта?
Angular
19. Как проводится конфигурация NgZone-модуля? Когда это необходимо?
20. Что раздражает в фреймворке? Что бы вы изменили?
21. Если бы вы решали, что добавить в следующем релизе фреймворка, какая фича это была бы?
22. Писали ли вы кастомные декораторы? Если да, то зачем?
23. Сделать ревью кода и дать замечания по архитектуре.
24. Расскажите, как бы вы делали такие фичи. Опишите архитектуру фичи в приложении.
Back-end
25. Сравните Common.js с AMD Modules и ES6 Imports.
26. Какой фреймворк выбрали бы для бэкенда, почему?
27. Опишите своими словами, как работает OAuth v2.
28. Есть проект с источниками памяти, как их обнаружить, устранить и предотвратить это в будущем?
29. Есть проект с performance issues, как их обнаружить, устранить и предотвратить в будущем?
Базы данных
30. Какие альтернативные виды баз данных используете?
31. Что такое RDS и почему он иногда не подходит?
32. Что такое SQL Injections и как их избежать?
33. Почему для запросов в БД надо использовать плейсхолдеры?
34. Как спроектировать кластер на MongoDB?
35. Для чего используют MongoDB Aggregation framework?
36. Расскажите о GraphQL.
Инструменты
37. Можете ли вы описать суть методологии git flow в двух словах?
38. Что означает требование делать squash commits во время rebase?
39. Каково ваше мнение об альтернативных системы контроля версий (Version Control System)?
40. Какие конвенции знаете и используете для git?
41. Расскажите о своем опыте использования / внедрения CI / CD.
42. Необходимо настроить деплой проекту на несколько сред. Расскажите, как бы вы построили процесс? Какие инструменты использовали бы?
Практические задания
43. Реализуйте асинхронный метод filter для Array (должны работать await).
44. Реализуйте функцию reduce при помощи рекурсии.
45. Как можно было бы сделать toggle-компонент, как в iPhone, без использования JS?
Благодарим за помощь в подготовке статьи Вячеславу Колдовскому, Ивану Рыженку, Николаю Галкину, Александру Бурмистрову, Владу Балабашу, Андрею Шумаде, Ивану Кувацкому, Андрею Кладочному.
Javascript Questions and Answers has been designed with a special intention of helping students and professionals preparing for various Certification Exams and Job Interviews. This section provides a useful collection of sample Interview Questions and Multiple Choice Questions (MCQs) and their answers with appropriate explanations.
Sr.No. | Question/Answers Type |
---|---|
1 | Javascript Interview Questions
This section provides a huge collection of Javascript Interview Questions with their answers hidden in a box to challenge you to have a go at them before discovering the correct answer. |
2 | Javascript Online Quiz
This section provides a great collection of Javascript Multiple Choice Questions (MCQs) on a single page along with their correct answers and explanation. If you select the right option, it turns green; else red. |
3 | Javascript Online Test
If you are preparing to appear for a Java and Javascript Framework related certification exam, then this section is a must for you. This section simulates a real online test along with a given timer which challenges you to complete the test within a given time-frame. Finally you can check your overall test score and how you fared among millions of other candidates who attended this online test. |
4 | Javascript Mock Test
This section provides various mock tests that you can download at your local machine and solve offline. Every mock test is supplied with a mock test key to let you verify the final score and grade yourself. |
Javascript Questions and Answers has been designed with a special intention of helping students and professionals preparing for various Certification Exams and Job Interviews. This section provides a useful collection of sample Interview Questions and Multiple Choice Questions (MCQs) and their answers with appropriate explanations.
Sr.No. | Question/Answers Type |
---|---|
1 | Javascript Interview Questions
This section provides a huge collection of Javascript Interview Questions with their answers hidden in a box to challenge you to have a go at them before discovering the correct answer. |
2 | Javascript Online Quiz
This section provides a great collection of Javascript Multiple Choice Questions (MCQs) on a single page along with their correct answers and explanation. If you select the right option, it turns green; else red. |
3 | Javascript Online Test
If you are preparing to appear for a Java and Javascript Framework related certification exam, then this section is a must for you. This section simulates a real online test along with a given timer which challenges you to complete the test within a given time-frame. Finally you can check your overall test score and how you fared among millions of other candidates who attended this online test. |
4 | Javascript Mock Test
This section provides various mock tests that you can download at your local machine and solve offline. Every mock test is supplied with a mock test key to let you verify the final score and grade yourself. |