❓👨💻 Вопросы для подготовки к собеседованию по JavaScript. Часть 2
Продолжаем разбирать вопросы для джунов: рассказываем о прототипном наследовании, цикле событий, методах сохранения данных в браузере, конструкторах, генераторах, функциональных выражениях, микро- и макрозадачах.
21. Что такое DOM?
DOM (Document Object Model) – это модель, которая представляет HTML-документ в виде дерева тегов. Каждый HTML-тег в этом дереве является объектом.
Вложенные теги являются дочерними элементами по отношению к своему
родительскому элементу. Текст внутри тега также является объектом. Все эти объекты
доступны для любых манипуляций с помощью JavaScript, а эти манипуляции, в свою очередь, позволяют
динамически управлять содержимым страницы. В приведенном ниже примере мы
выбираем элемент с классом "story"
и сохраняем его в переменной
story.
Затем мы выбираем элементы с id "set-text"
и
"clear-text"
и добавляем им обработчики событий. Когда на элемент с
id "set-text"
нажимают, текстовое содержимое элемента с классом
"story"
меняется на "Ночь 31 декабря началась снегопадом и
метелью."
Когда нажимают на элемент с id "clear-text"
,
текстовое содержимое элемента с классом "story"
очищается:
22. Что такое цикл событий?
Цикл событий в JavaScript – это механизм, который управляет выполнением кода. Он обеспечивает обработку событий и выполнение задач в правильном порядке. Хотя JavaScript работает в однопоточной среде, цикл событий дает возможность обрабатывать асинхронные операции и предотвращает блокировку основного потока выполнения.
Когда асинхронная операция (например, запрос к серверу) завершается, она помещает соответствующее событие в очередь событий. Цикл событий обрабатывает задачи в порядке их поступления. Он берет событие из очереди и передает его для выполнения. Если событие содержит обратный вызов или обработчик – вызывается соответствующая функция для выполнения кода, связанного с этим событием. Цикл событий также обрабатывает задачи, связанные с таймерами и промисами. Благодаря циклу событий, JavaScript быстро реагирует на действия пользователя и эффективно использует ресурсы при работе с асинхронными операциями .
В приведенном ниже примере, несмотря на то, что setTimeout(firstTask, 0)
имеет время ожидания 0
секунд, первая задача firstTask()
все равно не будет выполнена сразу после secondTask()
. Это происходит потому, что JavaScript использует цикл событий для управления выполнением асинхронных операций. Когда мы вызываем setTimeout()
, функция firstTask()
помещается в очередь событий, – цикл событий начинает обрабатывать эту функцию, когда стек вызовов опустеет.
23. Что такое прототипное наследование?
Прототипное наследование в JavaScript – это механизм, который позволяет одному объекту наследовать свойства и методы другого объекта. Это основной способ наследования в JavaScript.
Каждый объект в
JavaScript имеет внутреннее скрытое свойство prototype
, которое ссылается на другой объект. Этот
другой объект называется прототипом первого объекта. При попытке получить доступ к свойству объекта,
JavaScript сначала проверяет, есть ли это свойство в самом объекте. Если нет,
он ищет его в прототипе объекта. Если и там его нет, то в прототипе прототипа и
так далее. Если свойство или метод отсутствуют в объекте и его прототипе, JavaScript вернет undefined
:
24. Для чего нужен оператор опциональной последовательности?
Оператор
опциональной последовательности ?.
позволяет получить безопасный доступ к
вложенным свойствам объекта – даже в том случае, когда промежуточное свойство
отсутствует. Оператор ?.
прекращает оценку и возвращает undefined
, если часть
после ?.
является либо undefined
, либо null
.
25. Что такое теневой DOM?
Shadow DOM – это техника, позволяющая создавать изолированные фрагменты HTML и CSS в специальном сегменте DOM, который находится внутри определенного элемента. Такой подход позволяет исключить влияние инкапсулированных стилей на структуру и внешний вид основной страницы, и обеспечивает большую гибкость и контроль над представлением и поведением элементов.
В приведенном ниже примере инкапсулированные стили пользовательского элемента не влияют на внешний вид остальной части страницы:
26. Что такое рекурсия и как ее можно использовать в JavaScript?
Рекурсия в программировании – это процесс, в котором функция вызывает саму себя. Рекурсия обычно используется для решения задач, которые можно разбить на более простые подзадачи. В JavaScript рекурсию можно использовать, например, для работы с многоуровневыми массивами и обхода деревовидных структур данных.
Так можно преобразовать вложенный массив в одномерный:
А так можно обойти и визуализировать дерево:
Результат:
27. В чем разница между объявлением функции и функциональным выражением?
Объявление функции и функциональное выражение – это два способа определения функций в JavaScript.
Объявление функции – это традиционный способ определения функции. Функция создается и присваивается переменной, как любое другое значение. При этом объявленные функции доступны во всем коде, даже до того, как программа достигает того участка, где они определены:
Функциональное выражение – это альтернативный способ определения функции:
В отличие от традиционной функции, функциональное выражение нельзя вызывать до определения в коде – это приведет к ошибке . Функциональные выражения могут:
- быть анонимными;
- формировать замыкания;
- передаваться в качестве аргументов другим функциям;
- использоваться как немедленно вызываемые функциональные выражения (IIFE).
28.Что такое функции-конструкторы?
Конструкторы в JavaScript – это специальные функции, используемые для создания объектов. Вот два основных правила при работе с конструкторами:
- Имя конструктора должно начинаться с заглавной буквы.
- Конструктор вызывается при помощи оператора
new
.
Когда мы вызываем
конструктор через new
, происходит следующее:
- Создается новый пустой объект и присваивается в
this
. - Выполняется код внутри конструктора. Обычно он модифицирует объект
this
, добавляя в него свойства. - Значение
this
возвращается из конструктора как результат.
Например:
Здесь User – функция-конструктор. Когда мы
вызываем конструктор через new User("Вася")
,
создается объект user
с
указанным именем и методом sayHi
. Таким образом с помощью конструкторов можно многократного создавать
объекты по одному шаблону.
29. Как получить список ключей и значений объекта?
В JavaScript для получения списка ключей и значений объекта используются методы Object.keys() и Object.values().
Object.keys() возвращает массив со всеми ключами объекта:
Object.values() возвращает массив со всеми значениями свойств объекта:
Используя Object.keys() и Object.values(), можно сделать
перебор:
Или вывести ключи и значения в виде объекта:
30. Приведите примеры нововведений, добавленных в JavaScript в версии ES6
В ES6 множество нововведений, вот всего несколько примеров.
Деструктуризация объектов и массивов:
Шаблонные строки:
Стрелочные функции:
Параметры по умолчанию:
Объявление переменных с помощью let и const.
let – аналог var, но с блочной областью видимости:
const – объявление константы (переменной, которую нельзя изменить):
Оператор распространения (позволяет распаковывать элементы массива или объекта для аргументов функции или создания новых массивов/объектов):
31. Как происходит наследование классов в ES6?
Наследование классов в ES6 осуществляется с помощью ключевого слова extends
, которое следует за именем родительского класса. Родительский класс часто называют базовым классом, а класс, который наследует базовый/родительский класс, называется производным или дочерним:
32. Что такое микрозадачи и макрозадачи?
В JavaScript микрозадачи и макрозадачи относятся к типам задач, которые должны выполняться в цикле событий.
Микрозадачи – это задачи, которые должны быть выполнены в текущем цикле событий перед тем, как браузер перерисует страницу. Они обычно добавляются в очередь выполнения с помощью методов, таких как Promise.then(), process.nextTick() (в Node.js) или MutationObserver. Примеры микрозадач – выполнение обработчиков промисов и мутации DOM.
С другой стороны, макрозадачи – это задачи, которые должны быть выполнены после окончания текущего цикла событий и перед тем, как изменения будут отрендерены на экране. Это включает задачи, добавленные в очередь событий с помощью setTimeout, setInterval, requestAnimationFrame, а также обработку входных событий и сетевых запросов. Макрозадачи выполняются после того, как завершается обработка всех микрозадач в текущем цикле событий.
Разница между микрозадачами и макрозадачами определяет порядок выполнения и позволяет управлять приоритетами различных задач в JavaScript. Микрозадачи имеют более высокий приоритет и выполняются до макрозадач, что позволяет быстрее обновлять интерфейс и предотвращает блокировку основного потока выполнения JavaScript. В приведенном ниже примере setTimeout является макрозадачей, а Promise.then() – микрозадачей. Поскольку микрозадачи имеют более высокий приоритет, Promise.then() выполняется перед setTimeout, и поэтому promise появляется в первую очередь:
33. Что такое генераторы?
Генераторы в JavaScript представляют собой специальный тип функций, которые генерируют последовательность значений по одному за раз по мере необходимости, и позволяют приостанавливать и возобновлять свое выполнение (в отличие от обычных функций, которые выполняются до завершения). Генераторы хорошо работают с объектами и упрощают создание потоков данных.
Чтобы объявить генератор, используют специальный синтаксис – функцию-генератор. Функция-генератор определяется с помощью символа *
после ключевого слова function:
Генератор возвращает итератор, который можно использовать для контроля над выполнением функции. Основной метод итератора – next(). Когда вызывается next(), выполнение кода продолжается до ближайшего оператора yield. Когда достигнут yield, выполнение функции приостанавливается, и соответствующее значение возвращается во внешний код.
34. Какие существуют методы для сохранения данных в браузере?
Есть 3 основных метода хранения данных в браузере:
- LocalStorage и SessionStorage используются для хранения пар ключ-значение. Данные, сохраненные в них, сохраняются после обновления страницы. При этом только LocalStorage может сохранять данные после перезапуска браузера. Оба хранилища могут использовать только строки в качестве ключей и значений, поэтому объекты необходимо преобразовать с помощью JSON.stringify().
- Cookie – небольшие строки данных, которые хранятся в браузере. Cookie обычно устанавливаются веб-сервером с использованием заголовка Set-Cookie. Браузер затем автоматически добавляет их почти ко всем запросам на тот же домен с использованием заголовка Cookie. Один экземпляр cookie может содержать до 4 кб данных. В зависимости от браузера, допускается более 20 cookie на сайт.
- IndexedDB – встроенная база данных, более мощная, чем localStorage. Это NoSQL-хранилище данных в формате JSON внутри браузера, где доступны несколько типов ключей, а значения могут быть практически любым. IndexedDB поддерживает асинхронный доступ, транзакции для обеспечения согласованности данных и создание индексов для эффективного поиска. Позволяет хранить больше данных, чем localStorage, может быть связана с Service Workers и другими технологиями, которые обеспечивают функционирование PWA в оффлайне.
Вот примеры использования каждого из этих методов хранения данных:
35. В чем заключается разница между sessionStorage и localStorage?
Сессионное хранилище sessionStorage и локальное хранилище localStorage позволяют сохранять данные в формате ключ-значение в браузере. Оба они используются для хранения данных на стороне клиента, но имеют некоторые отличия:
- Объем хранимых данных – localStorage может хранить до 10 МБ данных, в то время как sessionStorage может хранить только до 5 МБ данных.
- Срок хранения данных – в localStorage данные не удаляются, когда закрывается браузер или вкладка. И напротив, данные в sessionStorage удаляются, когда закрывается вкладка или окно браузера.
- Доступность данных – из localStorage данные доступны в любом окне браузера, в то время как данные из sessionStorage доступны только из того же окна браузера, где они были сохранены.
Пример использования localStorage:
Пример использования sessionStorage:
36. Что такое регулярные выражения?
Регулярные выражения (regex) – это паттерны, которые используются для поиска и замены текста в строках. В паттернах используются комбинации специальных символов (шаблоны) и флаги (модификаторы, которые определяют поведение поиска). Регулярные выражения часто используют в комбинации с этими методами:
- test() – проверка на соответствие шаблону
- match() – поиск соответствий
- replace() – замена по шаблону
- search() – поиск индекса
Составлять регулярные выражения можно с помощью конструктора RegExp или литеральной нотации.
Пример определения email-адреса в строке с помощью конструктора RegExp:
Пример извлечения телефонного номера с помощью литеральной нотации:
37. В чем заключается разница между WeakSet, WeakMap и обычными Set и Map?
WeakSet и WeakMap – это специальные структуры данных в JavaScript, которые отличаются особенностью хранения ссылок на объекты.
В обычных Set и Map хранятся сильные ссылки на объекты. Это значит, что пока существует ссылка на объект в этих структурах, сборщик мусора не удалит этот объект из памяти, даже если больше нигде в коде нет ссылок на него.
И напротив, в WeakSet и WeakMap хранятся слабые ссылки. Это означает, что если объект, на который есть ссылка в этих структурах, больше недоступен в коде (т.е. нигде больше нет сильных ссылок на него), то сборщик мусора может удалить этот объект из памяти, даже если в WeakSet или WeakMap все еще есть ссылка на него. Таким образом, использование слабых ссылок позволяет не держать в памяти ненужные больше объекты и экономить память.
Кроме того, в WeakMap в качестве ключей могут использоваться только объекты, а не примитивные значения. А в WeakSet хранятся только объекты, без ключей.
38. Почему два объекта с одинаковыми полями возвращают false при сравнении?
В JavaScript объекты сравниваются по ссылкам на область памяти, где они хранятся. Два разных объекта, даже если у них одинаковые поля и значения этих полей, располагаются в разных областях памяти. Например, у нас есть:
Хотя у этих двух объектов одно и то же поле fruit
со значением 'яблоко'
, на самом деле это два абсолютно разных объекта, которые хранятся в разных ячейках памяти. Поэтому если мы сравним их, результат будет false
. Для того чтобы два объекта считались равными, нужно, чтобы это был один и тот же объект, то есть чтобы обе переменные ссылались на одну и ту же область памяти.
39. Как в JavaScript реализованы методы примитивных типов данных?
JavaScript позволяет работать с примитивными типами данных – строками, числами, логическими значениями – как с объектами, поскольку у них тоже есть методы. Например, у строк есть методы toUpperCase() и toLowerCase(), у чисел есть методы toFixed() и toPrecision() и т.д.
Эта возможность реализована благодаря специальным оберточным объектам для каждого примитивного типа данных. Эти объекты называются:
- String – для строк
- Number – для чисел
- Boolean – для логических значений
- Symbol – для символов
Когда мы вызываем метод у примитивного значения, например "test".toUpperCase()
, происходит следующее:
- Создается временный оберточный объект типа
String
со значением"test"
. - У этого объекта вызывается метод
toUpperCase()
. - Результат возвращается обратно в примитивное значение.
- Временный оберточный объект удаляется.
Таким образом реализуется возможность использовать методы у примитивных типов данных. Благодаря этому механизму, примитивы в JavaScript ведут себя как объекты.
40. Как проверить, из какого класса был создан объект?
Для этого в JavaScript используется оператор instanceof. Он позволяет проверить, из какого класса был создан объект, учитывая наследование.
Например, есть базовый класс Animal и классы-наследники Dog и Cat:
Создадим объект класса Dog и проверим с помощью оператора instanceof
, является ли объект экземпляром указанного класса или классов-родителей: