Junior Level

Junior уровень

Общие вопросы

Какие методы HTTP-запросов вы знаете?

HTTP определяет набор методов запроса, указывающих, какое действие выполнить для данного ресурса. Некоторые из наиболее используемых методов:

  • GET: Извлекает информацию о ресурсе. GET-запросы должны быть идемпотентными и безопасными, что означает, что их вызов не должен приводить к каким-либо изменениям на сервере.
  • POST: Отправляет данные на сервер для создания нового ресурса. POST-запросы не являются идемпотентными, они могут приводить к разным результатам при повторном вызове.
  • PUT: Заменяет целевой ресурс данными, представленными в запросе.
  • DELETE: Удаляет целевой ресурс.
  • PATCH: Применяет частичные изменения к ресурсу.
  • HEAD: Идентичен GET, но сервер отвечает только заголовками.
  • OPTIONS: Используется для описания опций связи для целевого ресурса.
  • CONNECT: Устанавливает сетевое соединение для целевого ресурса, обычно используется для HTTPS-туннелей.
  • TRACE: Получает трассировочный маршрут к целевому ресурсу.

Какие версии HTTP-протокола вам известны?

  • HTTP/1.0: Это первая версия HTTP. Поддерживает только методы GET, HEAD и POST, а каждое соединение закрывается после одного запроса и ответа.
  • HTTP/1.1: Во второй версии поддерживается постоянное соединение, что увеличивает производительность. Кроме того, поддерживаются дополнительные методы, такие как PUT, DELETE и OPTIONS. -
  • HTTP/2: Следующее поколение HTTP, в первую очередь обеспечивающее улучшение производительности (например, HTTP-мультиплексирование и HTTP-поток), а также улучшает поддержку текстовых протоколов.
  • HTTP/3: Последний HTTP-протокол, который обычно еще в разработке. Он предлагает улучшенные методы мультиплексирования и передачи потоков относительно HTTP/2, он также использует протокол UDP вместо TCP.

Какие знаете коды ответа (состояния) HTTP?

В HTTP определены классы статусов, которые имеют определенный диапазон. Перечень некоторых основных и часто используемых HTTP-кодов:

  • 2xx Успешно: Этот класс статусов указывает, что клиентский запрос был успешно получен, понят и принят. Например, 200 OK, 201 Created, 202 Accepted.
  • 3xx Перенаправление: Этот класс статусов указывает, что для выполнения запроса необходимо выполнить дополнительное действие. Например, 301 Moved Permanently, 302 Found, 304 Not Modified.
  • 4xx Ошибка клиента: Этот класс статусов указывает, что запрос содержит неправильный синтаксис или не может быть выполнен. Например, 400 Bad Request, 401 Unauthorized, 404 Not Found.
  • 5xx Ошибка сервера: Этот класс статусов указывает, что сервер не смог выполнить действие. Например, 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable.

Что такое Cross-Origin Resource Sharing? Как устранить проблемы с CORS?

Это механизм, который использует дополнительные HTTP-заголовки для сообщения браузеру, что ему могут разрешить доступ к выбранным ресурсам с сервера на источнике (домене), отличном от того, что текущий. Проблемы с CORS обычно могут быть устроены с помощью настройки правильных заголовков HTTP на сервере.

Что такое cookie?

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

Какой максимальный размер cookie?

Спецификация RFC 6265 для браузера предписывает, что он должен быть способен обрабатывать хотя бы 4096 байт (включая имя, значение, дату истечения, путь и домен) в одном куки и хотя бы 50 кук в одном домене.

Что означает директива use strict?

Это литеральное выражение, доступное в ECMAScript 5 и более поздних версиях, используется для включения строгого режима, который помогает в обнаружении потенциальных проблем в коде. В строгом режиме нельзя, например, использовать переменные, не объявив их, и не удается удалить переменные, функции и аргументы функций.

Чем JS отличается при работе на front-end и back-end?

Основное различие заключается в среде, где исполняется код. JavaScript на фронтенде выполняется в браузере, а на бэкенде - на сервере. Это ведет к доступности различных API и объектов в разных средах. Например, на фронтенде напрямую доступен Document Object Model (DOM), который позволяет взаимодействовать и манипулировать содержимым веб-страницы. На бэкенде (например, при использовании Node.js) доступны API для работы с файловой системой, сетью и т.д.

Что такое статическая и динамическая типизации?

В статической типизации типы данных переменных известны на этапе компиляции. Это означает, что их типы проверяются до выполнения программы во время компиляции. Языки, такие как C++, Java и Go, являются статически типизированными. В динамической типизации типы данных переменных могут изменяться в процессе выполнения программы. Языки, такие как Python, Ruby и, конечно, JavaScript являются динамически типизированными.

Как клиент взаимодействует с сервером?

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

Что такое REST?

REST описывает принципы, по которым предназначены или конструированы веб-сервисы. Идея REST заключается в том, что каждый URL представляет собой некоторый объект или ресурс, который можно получить или от которого можно избавиться. RESTful сервисы обычно используют HTTP методы, такие как GET для получения ресурсов, POST для создания новых ресурсов, PUT для обновления существующих и DELETE для их уничтожения. В REST декларативно указано состояние системы в каждый период времени, и все переходы между состояниями определяются явно.

Объяснить понятие мутабельность/иммутабельность? Какие типы являются мутабельными и наоборот?

Мутабельность и иммутабельность относятся к возможности изменения данных после их создания. Если объект мутабельный, его можно изменить после создания. Для контраста, если объект иммутабельный, его нельзя изменить после создания.

  • В JavaScript, например, примитивные типы (Number, String, Boolean, Null, Undefined, Symbol) являются иммутабельными, т.е. когда их значения изменяются, создается на самом деле новый объект с новым значением. На другой стороне объекты, массивы и функции являются мутабельными, т.е. их значения или свойства могут изменяться в любое время.
  • Иммутабельность особенно ценится в функциональном программировании и в случаях, когда требуется контролировать побочные эффекты. Если данные иммутабельны, вы можете быть уверены, что они не изменятся, что упрощает понимание и отладку кода.

JS Core

Типы данных в JavaScript

В JavaScript существует восемь основных типов данных:

  • Number: Для цифр. К нему относится и обычное число 10, и число с плавающей точкой 10.5, и специальные символические значения вроде Infinity, -Infinity и NaN ("not a number").
  • BigInt: Для целых чисел произвольной длины. Может использоваться для представления чисел, которые превышают максимально безопасное значение Number.
  • String: Для строк. Представление текста как последовательности символов.
  • Boolean: Для true/false.
  • Null: Этот тип имеет единственное значение null.
  • Undefined: Этот тип имеет единственное значение undefined. Обычно он означает, что значение не было присвоено.
  • Object: Для более сложных структур данных.
  • Symbol: Для уникальных идентификаторов.

Проверка, является ли объект массивом

В JavaScript для проверки, является ли объект массивом, можно использовать функцию Array.isArray(). Например:

let arr = [1, 2, 3];
console.log(Array.isArray(arr)); // выводит true

Проверка конечности числа

В JavaScript для проверки, является ли число конечным, используется функция isFinite(). Например:

console.log(isFinite(123)); // выводит true
console.log(isFinite(-Infinity)); // выводит false

Проверка равенства переменной NaN

В JavaScript при проверке NaN с помощью оператора равенства возвращается False, даже если мы сравниваем NaN с самим собой. Поэтому для проверки, является ли значение NaN, используется функция Number.isNaN(). Например:

let var1 = NaN;
console.log(Number.isNaN(var1)); // выводит true

Разница между isNaN() и Number.isNaN();

  • isNaN() преобразует переданный параметр в число и затем тестирует его на NaN. Это означает, что некоторые значения, которые не являются числами, вроде строки, будут преобразованы в числа и в результате вернут значение false.
  • Number.isNaN() не преобразует переданный параметр. Если переданное значение не является числом, то функция вернёт false. Если значение является числом и равно NaN, то будет возвращено значение true.

Сравнение var, let, const

  • var: Объявляет переменную, опционально инициализируя её значением. Область видимости переменных, объявленных с помощью var, ограничена телом текущего функционального блока.
  • let: Объявляет переменную с ограниченной областью видимости в блоке, выражении, или объявленная переменная может быть опционально инициализирована значением. Она не может быть объявлена повторно в том же блоке.
  • const: Объявляет константу, которая является ссылкой на значение. Так как значение является ссылкой, само значение может быть изменяемым; это называется изменяемостью объекта (Mutability), а это отличается от присваивания JavaScript, которое является неизменным.

Область видимости:

Область видимости определяет, где и как переменная (имя, которое указывает на значение) может быть доступна в вашем коде. В JavaScript есть три типа областей видимости:

  • Глобальная область видимости: Переменная, объявленная вне функции, имеет глобальную область видимости и может быть отображена и изменена из любого места вашего кода.
  • Локальная область видимости или функциональная область видимости: Переменная, объявленная внутри функции, может быть просмотрена и изменена только внутри этой функции.
  • Блочная область видимости: let и const ограничивают область видимости переменной до блока кода, в котором она была объявлена.

Деструктуризация

Это особенность JavaScript, позволяющая извлекать данные из массивов, объектов и множеств прямо в отдельные переменные, что делает работу с этими структурами данных удобнее и читабельнее.

Пример с массивом:

let [first, second, third] = ["apple", "banana", "cherry"];
console.log(first); // выводит "apple"

Пример с объектом:

let { name, age } = { name: "John", age: 30 };
console.log(name); // выводит "John"

Методы setTimeout и setInterval

  • setTimeout(function, delay, ...args): Используется для выполнения функции или кода в указанный отложенный период времени (однократно).
  • setInterval(function, delay, ...args): Используется для выполнения функции или кода повторно, с указанным интервалом времени между каждым вызовом.

Сравнение подходов асинхронного кода

  • Callbacks: Ранний метод асинхронного программирования в JavaScript. Callback-функция передается в другую функцию и выполняется после выполнения задачи. Минус — трудность в управлении ошибками и управлении множественными асинхронными вызовами (т.н. "callback hell").
  • Promises: Они решают проблемы обратных вызовов, предоставляя объект Promise, который представляет конечное состояние асинхронной операции. Обеспечивает улучшенный контроль над асинхронной ошибкой и позволяет организовывать код асинхронных операций последовательно.
  • async/await: Синтаксический сахар для работы с Promises. Обеспечивает более читаемый и чистый код, но под капотом все еще использует Promises.

Расширение прототипов стандартных классов

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

Например, расширим класс Array методом last, который будет возвращать последний элемент массива:

Array.prototype.last = function () {
  return this[this.length - 1];
};
 
// Использование:
let array = [1, 2, 3, 4, 5];
console.log(array.last()); // вывод: 5

Методы массива

  • push(): добавляет один или более элементов в конец массива и возвращает новую длину массива.
  • pop(): удаляет последний элемент из массива и возвращает его.
  • shift(): удаляет первый элемент из массива и возвращает его.
  • unshift(): добавляет один или более элементов в начало массива и возвращает новую длину.
  • forEach(), map(), filter(), reduce(), reduceRight(), every(), some(), find(), findIndex(): методы для перебора элементов массива.
  • sort(): сортирует элементы массива.
  • splice(), slice(): методы для изменения массива.
  • join(), concat(): методы для работы со строками и объединения массивов.

Методы перебора массива

  • forEach(): просто перебирает элементы массива.
  • map(): создает новый массив с результатами вызова функции для каждого элемента.
  • filter(): создает новый массив с элементами, прошедшими условие в функции.
  • reduce(), reduceRight(): применяет функцию к аккумулятору и каждому элементу массива (слева-направо или справа-налево), чтобы свести его к одному единственному значению.
  • every(): проверяет, удовлетворяют ли все элементы условию, заданному в передаваемой функции.
  • some(): проверяет, удовлетворяет ли хотя бы один элемент условию, заданному в передаваемой функции.
  • find(): возвращает первый найденный элемент, который удовлетворяет условию, заданному в передаваемой функции.
  • findIndex(): возвращает индекс первого найденного элемента, который удовлетворяет условию, заданному в передаваемой функции.

Операторы в JavaScript

  • Присваивание (=): назначает значение переменной.
  • Сравнение (==, ===, !=, !==, >, <, >=, <=): сравнивает значения.
  • Строчные (+): используется для конкатенации строк.
  • Арифметические (+, -, *, /, %): для выполнения арифметических операций.
  • Битовые (&, |, ^, ~, << , >>, >>>): оперируют на уровне двоичного представления чисел.

Коллекции Map и Set

  • Map: Коллекция пар ключ-значение. В отличие от объектов, ключами могут быть не только строки и символы, но и другие типы данных. Порядок элементов в Map — это порядок их добавления.
  • Set: Коллекция уникальных элементов. При добавлении уже существующего значения, Set не делает ничего и не дает ошибку. Порядок элементов в Set — это порядок их добавления.

Глубокая и поверхностная копии объекта

  • Поверхностная копия (Shallow Copy): создает новый объект и копирует в него все поля исходного объекта. Если поля исходного объекта содержат ссылки на другие объекты, то ссылки копируются, а не сами объекты. Это означает, что оба объекта будут ссылаться на одни и те же объекты.

Пример создания поверхностной копии:

let original = { a: 1, b: { c: 2 } };
let shallowCopy = { ...original };
  • Глубокая копия (Deep Copy): создаёт новый объект и рекурсивно копирует все поля исходного объекта в новый. Если поля исходного объекта включают ссылки на другие объекты, то также создаются новые копии этих объектов — на оригинальные объекты ссылок в копии не будет.

Пример создания глубокой копии:

let original = { a: 1, b: { c: 2 } };
let deepCopy = JSON.parse(JSON.stringify(original));

Обратите внимание, что метод JSON.parse(JSON.stringify(object)) работает только для JSON-безопасных объектов — объектов, которые могут быть сериализованы в формат JSON и обратно без потери данных.

Разница между function declaration и function expression

  • Декларация функции (Function Declaration): Назначает имя функции и может быть вызвана в любом месте кода, даже перед объявлением. Это возможно благодаря механизму подъема или hoisting.
function myFunction() {
// тело функции
}
  • Функциональное выражение (Function Expression): Функция объявляется в контексте какого-либо выражения и доступна только после ее объявления.
let myFunction = function () {
// тело функции
};

Анонимная функция

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

let myFunction = function() {
// тело функции
};

Стрелочные функции (Arrow Function)

  • Имеют более сжатый синтаксис по сравнению с обычными функциями.
  • Не создают своего контекста выполнения, а используют this из внешнего контекста.
  • Не могут быть использованы как конструкторы и не имеют своего arguments объекта.
let myFunction = (arg1, arg2) => {
// тело функции
};

IIFE

это функция, которая выполняется сразу же после определения. Обычно используется для создания изолированного скоупа переменных, чтобы избежать загрязнения глобального пространства имен.

(function () {
  // тело функции
})();

Hoisting

это механизм в JavaScript, когда переменные и объявления функций перемещаются на верх своей области видимости перед выполнением кода. Так переменные и функции можно использовать до того, как они объявлены в коде. Для переменных "hoisting" работает только с декларациями переменных, не с их инициализацией.

Замыкание (Closure) —

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

Как вы понимаете замыкания? Что будет выведено в консоли в этом случае?

var f = function () {
  console.log(1);
};
 
var execute = function (f) {
  setTimeout(f, 1000);
};
execute(f); // что выведет в консоль и почему
 
f = function () {
  console.log(2);
};

Замыкания — это функция, замкнута со всеми ее внешними переменными. Это значит, что функция "запоминает" окружение, в котором была создана.

В данном примере в консоли будет выведено "1". Функция execute принимает функцию в качестве аргумента и вызывает ее через setTimeout. Обратите внимание, что execute(f) вызвано перед переопределением f. Таким образом, когда execute(f) вызывается, f ссылается на первую функцию, которая выводит "1". Изменение f после вызова execute(f) не влияет на то, какая функция была передана в execute.

Что такое рекурсия?

Рекурсия — это процесс, в котором функция вызывает саму себя напрямую или косвенно. Это обычно делается для решения задач, которые можно разбить на более мелкие подзадачи того же типа.

Что означает ключевое слово this?

Ключевое слово this — это контекст вызова функции. Это означает, что this обычно ссылается на объект, к которому применяется функция. Значение this определяется в момент вызова функции и может меняться в зависимости от контекста, в котором вызывается функция.

Что такое потеря контекста?

Потеря контекста происходит, когда значение this становится не то, что вы ожидаете. Это обычно происходит, когда функция вызывается в контексте, отличном от того, в котором была определена. Это можно предотвратить, используя методы bind, call или apply, а также стрелочные функции, которые не имеют собственного this, а берут его из внешнего контекста.

Методы функций bind / call / apply?

  • call и apply вызывают функцию немедленно с заданным контекстом и аргументами. Разница между ними в том, как они принимают аргументы: call принимает список аргументов, apply принимает один массив аргументов.
  • bind создаёт новую функцию, которая при вызове устанавливает в качестве контекста выполнения this переданный объект и также может принимать пред оопределенные аргументы. Эта функция может быть вызвана позже, она сохраняет заданный контекст и переданные аргументы.
function greeting() {
  console.log(`Hello, my name is ${this.name}`);
}
 
let person = { name: "John" };
 
// call
greeting.call(person); // Hello, my name is John
 
// apply
greeting.apply(person); // Hello, my name is John
 
// bind
let boundGreeting = greeting.bind(person);
boundGreeting(); // Hello, my name is John

Общие по фронтенду

Что такое DOM?

DOM (Document Object Model) — это специальная древовидная структура, которая позволяет управлять HTML-разметкой из JavaScript-кода. Управление обычно состоит из добавления и удаления элементов, изменения их стилей и содержимого.

Браузер создаёт DOM при загрузке страницы, складывает его в переменную document и сообщает, что DOM создан, с помощью события DOMContentLoaded. С переменной document начинается любая работа с HTML-разметкой в JavaScript.

Сравните атрибуты подключения скрипта async и defer в HTML-документе.

  • async: Скрипт выполняется асинхронно. Это означает, что он не блокирует отрисовку страницы и работает в фоновом режиме. Когда скрипт загружен и готов к выполнению, он выполняется немедленно.
  • defer: Скрипт также загружается асинхронно, но выполняется только после того, как весь HTML-документ будет полностью загружен.

Какая разница между свойствами HTML-элементов innerHTML и innerText?

  • innerHTML: Возвращает или задает HTML-содержимое элемента в виде строки.
  • innerText: Возвращает или задает текстовое содержимое элемента без HTML-тегов.

Опишите процесс всплытия (bubbling) событий в DOM.

Это процесс, при котором событие первоначально срабатывает на самом вложенном элементе, а затем перемещается по дереву вверх к родителю, затем к родителю родителя и так далее до document и window.

    <body>
    <div id="parent">
        Parent
        <div id="child">Child</div>
    </div>
    </body>
 
    <script>
    let parent = document.getElementById('parent');
    let child = document.getElementById('child');
 
    parent.addEventListener('click', () => {
        console.log('Parent Clicked');
    });
 
    child.addEventListener('click', (event) => {
        console.log('Child Clicked');
        event.stopPropagation(); // Остановка всплытия события
    });
    </script>

В этом примере, когда вы кликаете по внутреннему диву (дочерний элемент), сначала сработает обработчик события на дочернем элементе. Затем, обычно событие "всплывает" к родителю, и срабатывает обработчик на родительском элементе. Но мы используем event.stopPropagation(), чтобы остановить всплытие, и в результате обработчик на родительском элементе не срабатывает.

Как остановить всплытие (bubbling) события?

Остановить всплытие события можно, вызвав метод event.stopPropagation() в обработчике события.

Как остановить дефолтную обработку события?

Чтобы отменить стандартное поведение в ответ на событие, можно использовать метод event.preventDefault().

Чему равен this в обработчике событий (event handler)?

В обычном обработчике событий this указывает на элемент, на котором событие было запущено.

Что такое LocalStorage и SessionStorage? Какой максимальный размер LocalStorage?

Это объекты, предоставляемые браузером для хранения данных на клиентской стороне.

  • LocalStorage сохраняет данные без срока действия, данные сохраняются даже после закрытия браузера.
  • SessionStorage хранит данные только в рамках текущей сессии браузера.

Как и для LocalStorage, размер хранилища SessionStorage обычно составляет 5 МБ для каждого домена в большинстве современных браузеров. Тем не менее, размер может варьироваться в зависимости от браузера и настроек пользователя.

Как получить высоту блока? Его положение относительно границ документа?

  • Высоту элемента можно получить с помощью element.offsetHeight или element.clientHeight.
  • Для получения положения элемента относительно документа используют свойство element.getBoundingClientRect(), которое возвращает объект с информацией о позиции элемента.

Что такое webpack?

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