Вопросы на собеседовании по JavaScript
JavaScript [ 21 ]
- Типы данных в JS
- Ссылочный тип данных и примитивный
- Различие null / undefined
- Function declaration / expression
- Различие между const, let, var
- Hoisting / Поднятие
- Область видимости «Scope»
- Closure / Замыкание
- Ключевое слово «this»
- Функция-конструктор
- Рекурсия
- Promise / Обещания
- Promise API
- Async / Await
- Методы запросов
- Методы функций
- Event Loop
- Прототипы
- Методы массивов
- Методы строк
- API / Rest API / Restful API
Типы данных в JS
- String
- Number
- Boolean
- Undefined
- Null
- Bigint
- Symbol
- Object
Ссылочный тип данных и примитивный
Ссылочный тип данных отличается от
примитивного типа данных тем, что переменная, которая содержит ссылочный
тип данных, не хранит само значение, а лишь ссылку на место в памяти.
При присваивании значения другой переменной, она не копирует значение, а передает ссылку на место в памяти, где хранится это значение.
А примитивы хранятся в памяти напрямую в переменной, которая содержит это значение. При присваивании значения другой переменной, значение переменной копируется.
При присваивании значения другой переменной, она не копирует значение, а передает ссылку на место в памяти, где хранится это значение.
А примитивы хранятся в памяти напрямую в переменной, которая содержит это значение. При присваивании значения другой переменной, значение переменной копируется.
Различие null / undefined
undefined — означает, что переменная была
объявлена, но ей не было присвоено какое-либо значение.
undefined — также может быть возвращено функцией, если она не возвращает явное значение.
undefined — является дефолтным значением для параметров функции.
null — означет, что значение переменной явно установлено, как ничего.
undefined — также может быть возвращено функцией, если она не возвращает явное значение.
undefined — является дефолтным значением для параметров функции.
null — означет, что значение переменной явно установлено, как ничего.
Function declaration / expression
Function declaration — объявление
функции, которое начинается с ключевого слова function, за которым
следует имя функции, а затем тело самой функции.
Благодаря механизму «Поднятие / Hoisting» данный вид функций можно вызывать в любом месте документа.
Function expression — эта функция, которая объявлена с помощью переменной и не может быть вызвана до ее объявления.
Благодаря механизму «Поднятие / Hoisting» данный вид функций можно вызывать в любом месте документа.
Function expression — эта функция, которая объявлена с помощью переменной и не может быть вызвана до ее объявления.
Различие между const, let, var
Переменные объявленные через var
всплывают, это значит, что если мы обратимся к переменной еще до
момента ее объявления, то получим просто
undefined в случае же с
let и const мы увидем ошибки.
У них есть разная область видимости, у let и const область видимости — блочная, а у var она функциональная и за блоком значение переменной var будет доступно.
Разница между let и const заключается в том, что переменная объявленая через сonst становится константой и по идее ее невозможно переопределить, при попытке это сделать мы получим ошибку, при этом мы можем изменять значение свойства обьекта объявленные через const, но не переопределить полностью объект.
У них есть разная область видимости, у let и const область видимости — блочная, а у var она функциональная и за блоком значение переменной var будет доступно.
Разница между let и const заключается в том, что переменная объявленая через сonst становится константой и по идее ее невозможно переопределить, при попытке это сделать мы получим ошибку, при этом мы можем изменять значение свойства обьекта объявленные через const, но не переопределить полностью объект.
Hoisting / Поднятие
Hoisting — это механизм в JavaScript, в
котором переменные и объявления функций
function declaration, передвигаются вверх
своей области видимости перед тем, как код будет выполнен.
JavaScript — сначала объявляет, а уже затем инициализирует наши переменные, а это значит, что к переменным объявленные через var, а также к функциям объявленным, как function declaration можно получить доступ еще до объявления.
JavaScript — сначала объявляет, а уже затем инициализирует наши переменные, а это значит, что к переменным объявленные через var, а также к функциям объявленным, как function declaration можно получить доступ еще до объявления.
Область видимости «Scope»
Область видимости — в JavaScript
определяет доступность переменных и функций в различных частях кода.
Область видимости определяет, где и какие переменные и функции могут быть использованы в коде.
Существует 3 типа Областей видимости:
Глобальная — переменные и функции в данной области становятся глобальными и доступны в любом месте документа.
Фунциональная — переменные и функции объявленные внутри функций доступны только этой функции и всем вложенным в нее функциям.
Блочная — появилась в ES6, для переменных объявленных с помощью let и const, такая область видимости находится внутри фигурных скобок так называемого блока, даже если это обычный блок if / else, и эти переменные не будут доступны за пределом этой области видимости.
Область видимости определяет, где и какие переменные и функции могут быть использованы в коде.
Существует 3 типа Областей видимости:
Глобальная — переменные и функции в данной области становятся глобальными и доступны в любом месте документа.
Фунциональная — переменные и функции объявленные внутри функций доступны только этой функции и всем вложенным в нее функциям.
Блочная — появилась в ES6, для переменных объявленных с помощью let и const, такая область видимости находится внутри фигурных скобок так называемого блока, даже если это обычный блок if / else, и эти переменные не будут доступны за пределом этой области видимости.
Closure / Замыкание
Замыкание — возникает, когда функция внутри
другой функции использует переменные из внешней функции. В этом случае
внутренняя функция сохраняет ссылку на внешнюю область видимости, и
переменные из этой области видимости могут быть использованы внутри
внутренней функции, даже после того, как внешняя функция завершила свою
работу.
Ключевое слово «this»
this — это ключевое слово, которое ссылается
на текущий объект, в контексте которого выполняется код. Значение this
зависит от того, как вызывается функция или метод.
Например, если функция вызывается как метод объекта, то this ссылается на этот объект. Если функция вызывается без контекста, то this ссылается на глобальный объект window.
Если функция вызывается с использованием конструктора, то this ссылается на новый экземпляр объекта, созданный с помощью конструктора.
Также хочется упомянуть о this в стрелочных функциях.
Стрелочная функция — не имеет собственного контекста и если в таком случае прописать this то ссылаться ключевое слово будет на объект ближайший по иерархии. Такая особенность удобна, когда мы хотим передать в функцию внешний контекст.
Например, если функция вызывается как метод объекта, то this ссылается на этот объект. Если функция вызывается без контекста, то this ссылается на глобальный объект window.
Если функция вызывается с использованием конструктора, то this ссылается на новый экземпляр объекта, созданный с помощью конструктора.
Также хочется упомянуть о this в стрелочных функциях.
Стрелочная функция — не имеет собственного контекста и если в таком случае прописать this то ссылаться ключевое слово будет на объект ближайший по иерархии. Такая особенность удобна, когда мы хотим передать в функцию внешний контекст.
Функция-конструктор
Функция-конструктор — позволяет создавать
новые объекты по шаблону на основе других данных. При вызове функции
конструктора this принимает значение вновь созданного объекта, который
наполняется вследствие выполнения тела функции.
Рекурсия
Рекурсия — это процесс, при котором функция
вызывает саму себя в своем теле. Для выхода из функции должно быть
обязательно условие.
Promise / Обещания
Promise
— это объект, который используется для выполнения
асинхронных операций и управления их результатами.
Promise может находиться в трех состояниях:
ожидание — pending
выполнено успешно — fulfilled
отклонено — rejected
Promise — позволяет управлять асинхронными операциями с помощью методов — then, catch, finally.
Первый аргумент метода .then — функция, которая выполняется, когда промис переходит в состояние «fulfield» и получает результат.
Второй аргумент метода .then – функция, которая выполняется, когда промис переходит в состояние «rejected» и получает ошибку.
.catch — функция, которая выполняется, когда промис переход в состояние «rejected» и в качестве аргумента принимает объект ошибки — error.
.finally — функция, которая выполнится в любом случае.
Promise может находиться в трех состояниях:
ожидание — pending
выполнено успешно — fulfilled
отклонено — rejected
Promise — позволяет управлять асинхронными операциями с помощью методов — then, catch, finally.
Первый аргумент метода .then — функция, которая выполняется, когда промис переходит в состояние «fulfield» и получает результат.
Второй аргумент метода .then – функция, которая выполняется, когда промис переходит в состояние «rejected» и получает ошибку.
.catch — функция, которая выполняется, когда промис переход в состояние «rejected» и в качестве аргумента принимает объект ошибки — error.
.finally — функция, которая выполнится в любом случае.
Promise API
В классе Promise есть несколько статических
методов:
Promise.all — принимает массив промисов и возвращает новый промис. Новый промис завершится, когда завершится весь переданный список промисов, и его результатом будет массив их результатов. Если один промис завершается с ошибкой, то весь Promise.all завершается с ней, полностью забывая про остальные промисы в списке. Их результаты игнорируются.
Promise.race — Метод очень похож на Promise.all, но ждёт только первый выполненный промис, из которого берёт результат (или ошибку).
Promise.any — Метод очень похож на Promise.race, но ждёт только первый успешно выполненный промис, из которого берёт результат. Если ни один из переданных промисов не завершится успешно, тогда возвращённый объект Promise будет отклонён с помощью AggregateError – специального объекта ошибок, который хранит все ошибки промисов в своём свойстве errors.
Promise.allSettled — метод всегда ждёт завершения всех промисов.
В массиве результатов будет:
status: fulfilled, value — результат для успешных завершений,
status: rejected, reason — результат с ошибкой.
Promise.all — принимает массив промисов и возвращает новый промис. Новый промис завершится, когда завершится весь переданный список промисов, и его результатом будет массив их результатов. Если один промис завершается с ошибкой, то весь Promise.all завершается с ней, полностью забывая про остальные промисы в списке. Их результаты игнорируются.
Promise.race — Метод очень похож на Promise.all, но ждёт только первый выполненный промис, из которого берёт результат (или ошибку).
Promise.any — Метод очень похож на Promise.race, но ждёт только первый успешно выполненный промис, из которого берёт результат. Если ни один из переданных промисов не завершится успешно, тогда возвращённый объект Promise будет отклонён с помощью AggregateError – специального объекта ошибок, который хранит все ошибки промисов в своём свойстве errors.
Promise.allSettled — метод всегда ждёт завершения всех промисов.
В массиве результатов будет:
status: fulfilled, value — результат для успешных завершений,
status: rejected, reason — результат с ошибкой.
Async / Await
Существует специальный синтаксис для работы с промисами, который
называется «async / await».
Ключевое слово async перед функцией гарантирует, что эта функция в любом случае вернёт Promise.
Есть другое ключевое слово – await, которое использоуется внутри асинхронной функций.
Ключевое слово await заставит интерпретатор JavaScript ждать до тех пор, пока промис справа от await не выполнится. После чего оно вернёт его результат, и выполнение кода продолжится.
Ключевое слово async перед функцией гарантирует, что эта функция в любом случае вернёт Promise.
Есть другое ключевое слово – await, которое использоуется внутри асинхронной функций.
Ключевое слово await заставит интерпретатор JavaScript ждать до тех пор, пока промис справа от await не выполнится. После чего оно вернёт его результат, и выполнение кода продолжится.
Методы запросов
GET — получение данных с сервера
POST — запрос используется для отправки данных на сервер
PUT — используется для обновления данных
DELETE — удаление данных на сервере
PATCH — запрос используется для частичного обновления данных на сервере
POST — запрос используется для отправки данных на сервер
PUT — используется для обновления данных
DELETE — удаление данных на сервере
PATCH — запрос используется для частичного обновления данных на сервере
Методы функций
bind — создает новую функцию, которая
связывает указанный объект с контекстом вызова функции. Метод также может
принимать аргументы, которые будут переданы в вызываему функцию.
Дальнейшие вызовы функции будут вызваны уже с новым контекстом.
call — вызывает функцию с заданным контекстом, также call может принимать аргументы.
Метод apply аналогичен call, отличие лишь в том, что call принимает список аргументов, а apply — массив аргументов.
call — вызывает функцию с заданным контекстом, также call может принимать аргументы.
Метод apply аналогичен call, отличие лишь в том, что call принимает список аргументов, а apply — массив аргументов.
Event Loop
JavaScript является однопоточным языком
программированием, это значит, что JavaScript может выполнять только
одну задачу за одну единицу времени.
Event Loop — механизм, который определяет приоритеты, решает какую задачу куда направить и в какой момент времени.
! Важно отметить то, что данный механизм не является частью ЯП JavaScript.
В понятие Event Loop еще входят такие вещи, как — heap, call stack, WebApi, macrotask queue и microtask queue.
Heap ( куча ) — это некий участок памяти, выделяемый, под хранение объектов.
Когда Event Loop запускается, он циклически проходит через кучу, чтобы найти элементы, которые необходимо обработать.
Call stack — это то место куда попадает код, после чего происходит его исполнение.
Web Api — это интерфейс, предоставляемый браузером. С помощью него мы можем взаимодействовать с DOM-деревом, устанавливать таймеры, отслеживать клики по элементам, отправлять запросы.
Macrotask queue — это очередь макро задач, в которую попадают функции, события таймера, мыши, клавиатуры и http запросы.
Microtask queue — это очередь микро задач, отличие от макро задач в том что микро задачи будут выполняться до тех пор, пока они есть в очереди, и перед макро задачами им отдается приоритет, к таким задачам относятся — Promises.
Event Loop — механизм, который определяет приоритеты, решает какую задачу куда направить и в какой момент времени.
! Важно отметить то, что данный механизм не является частью ЯП JavaScript.
В понятие Event Loop еще входят такие вещи, как — heap, call stack, WebApi, macrotask queue и microtask queue.
Heap ( куча ) — это некий участок памяти, выделяемый, под хранение объектов.
Когда Event Loop запускается, он циклически проходит через кучу, чтобы найти элементы, которые необходимо обработать.
Call stack — это то место куда попадает код, после чего происходит его исполнение.
Web Api — это интерфейс, предоставляемый браузером. С помощью него мы можем взаимодействовать с DOM-деревом, устанавливать таймеры, отслеживать клики по элементам, отправлять запросы.
Macrotask queue — это очередь макро задач, в которую попадают функции, события таймера, мыши, клавиатуры и http запросы.
Microtask queue — это очередь микро задач, отличие от макро задач в том что микро задачи будут выполняться до тех пор, пока они есть в очереди, и перед макро задачами им отдается приоритет, к таким задачам относятся — Promises.
Прототипы
Прототипы — это
механизм, который позволяет объектам наследовать свойства и методы
других объектов. Каждый объект в JavaScript имеет свойство
__proto__, которое ссылается на его
prototype.
Prototype определяет набор свойств и методов, которые доступны объектам созданным через class или function.
Наследование в JavaScript происходит по цепочке прототипов. Если свойство или метод не найдены в текущем объекте, то JavaScript ищет его в его прототипе, затем в прототипе прототипа и так далее, пока не будет найден нужный элемент или не будет достигнут конец цепочки прототипов.
У примитивных типов данных (числа, строки, булевы значения) есть соответствующие объекты-обертки (Number, String, Boolean).
Таким образом, при создании объектов типа Array, String, Number и Boolean происходит наследование прототипов, что позволяет им использовать методы и свойства из соответствующих прототипов.
1. __proto__ разных объектов, но одинаковых по типу будет равен.
К примеру:
Аналогичный результат будет и при сравнении
proto у массивов, чисел, строк и т.п.
объектов.
2. Любой объект в JavaScript «под капотом» создается с помощью функции-конструктора или класса.3. __proto__ ссылается на прототип того
класса, от которого он был создал.
К примеру:4. Разный prototype одинаковых объектов не
равен друг другу.
Prototype определяет набор свойств и методов, которые доступны объектам созданным через class или function.
Наследование в JavaScript происходит по цепочке прототипов. Если свойство или метод не найдены в текущем объекте, то JavaScript ищет его в его прототипе, затем в прототипе прототипа и так далее, пока не будет найден нужный элемент или не будет достигнут конец цепочки прототипов.
У примитивных типов данных (числа, строки, булевы значения) есть соответствующие объекты-обертки (Number, String, Boolean).
Таким образом, при создании объектов типа Array, String, Number и Boolean происходит наследование прототипов, что позволяет им использовать методы и свойства из соответствующих прототипов.
1. __proto__ разных объектов, но одинаковых по типу будет равен.
К примеру:
let man = {} let man2 = {} console.log(man.__proto__ === man2.__proto__) // true
2. Любой объект в JavaScript «под капотом» создается с помощью функции-конструктора или класса.
let promise = new Promise(() => {}) // new Promise(...) let man = {} // new Object(...) let users = [] // new Array(...) let age = 18 // new Number(...) let name = 'Vasya' // new String(...) function myFunction() {} // new Function(...) let myFunctionExp = function() {} // new Function(...) let myFunctionArr = () => {} // new Function(...) class MyClass {} // new Function(...) let newClass = new MyClass() // new MyClass
К примеру:
let promise = new Promise(() => {}) promise.__proto__ === Promise.prototype // true let name = "name" name.__proto__ === String.prototype // true
function myFunc1 () {} function myFunc2 () {} myFunc1.prototype === myFunc2.prototype // false
Методы массивов
Для добавления и
удаления элементов:
push – добавляет элементы в конец.
pop – извлекает элемент с конца.
shift – извлекает элемент с начала.
unshift – добавляет элементы в начало.
splice (pos, deleteCount, ...items) – начиная с индекса pos удаляет deleteCount элементов и вставляет items.
slice (start, end) – создаёт новый массив, копируя в него элементы с индекса start до end (не включая end).
concat – возвращает новый массив: копирует все члены текущего массива и добавляет к нему items, если какой-то из items является массивом, тогда берутся его элементы.
Для поиска среди элементов:
indexOf — ищет в массиве указанный элемент и возвращает его позицию.
lastIndexOf — ищет в массиве последний указанный элемент и возвращает его позицию.
includes – возвращает true, если в массиве имеется элемент value, в противном случае false.
find — возвращает значение первого найденного в массиве элемента, которое удовлетворяет условию переданному в callback функции.
filter — фильтрует элементы через функцию и отдаёт все найденные элементы, возвращает новый массив.
findIndex — похож на find, но возвращает индекс вместо значения.
some — позволяет узнать, есть ли в массиве хотя бы один элемент, удовлетворяющий условию, возвращает булевое значение.
every — проверяет элементы массива в соответствии с переданной функцией. Метод возвращает true, если для всех элементов массива переданная функция вернет true, в противном случае метод возвращает false.
Для перебора элементов:
forEach – вызывает функцию для каждого элемента массива.
Для преобразования массива:
map – вызывает функцию для каждого элемента массива и возвращает новый массив результатов выполнения этой функции.
sort — позволяет отсортировать элементы массива в порядке возрастания или в соответствии с заданной функцией сравнения.
reverse – меняет порядок следования элементов на противоположный и возвращает изменённый массив.
split – он разбивает строку на массив по заданному разделителю.
join — создаёт строку из элементов arr, разделяя их аргументом.
reduce — используется для преобразования массива в одно значение путем применения функции к каждому элементу массива и аккумулирования результата.
reduceRight — работает аналогично методу reduce, но применяет функцию к элементам массива в обратном порядке, начиная с последнего элемента и заканчивая первым.
Дополнительно:
Array.isArray(arr) проверяет, является ли arr массивом.
push – добавляет элементы в конец.
pop – извлекает элемент с конца.
shift – извлекает элемент с начала.
unshift – добавляет элементы в начало.
splice (pos, deleteCount, ...items) – начиная с индекса pos удаляет deleteCount элементов и вставляет items.
slice (start, end) – создаёт новый массив, копируя в него элементы с индекса start до end (не включая end).
concat – возвращает новый массив: копирует все члены текущего массива и добавляет к нему items, если какой-то из items является массивом, тогда берутся его элементы.
Для поиска среди элементов:
indexOf — ищет в массиве указанный элемент и возвращает его позицию.
lastIndexOf — ищет в массиве последний указанный элемент и возвращает его позицию.
includes – возвращает true, если в массиве имеется элемент value, в противном случае false.
find — возвращает значение первого найденного в массиве элемента, которое удовлетворяет условию переданному в callback функции.
filter — фильтрует элементы через функцию и отдаёт все найденные элементы, возвращает новый массив.
findIndex — похож на find, но возвращает индекс вместо значения.
some — позволяет узнать, есть ли в массиве хотя бы один элемент, удовлетворяющий условию, возвращает булевое значение.
every — проверяет элементы массива в соответствии с переданной функцией. Метод возвращает true, если для всех элементов массива переданная функция вернет true, в противном случае метод возвращает false.
Для перебора элементов:
forEach – вызывает функцию для каждого элемента массива.
Для преобразования массива:
map – вызывает функцию для каждого элемента массива и возвращает новый массив результатов выполнения этой функции.
sort — позволяет отсортировать элементы массива в порядке возрастания или в соответствии с заданной функцией сравнения.
reverse – меняет порядок следования элементов на противоположный и возвращает изменённый массив.
split – он разбивает строку на массив по заданному разделителю.
join — создаёт строку из элементов arr, разделяя их аргументом.
reduce — используется для преобразования массива в одно значение путем применения функции к каждому элементу массива и аккумулирования результата.
reduceRight — работает аналогично методу reduce, но применяет функцию к элементам массива в обратном порядке, начиная с последнего элемента и заканчивая первым.
Дополнительно:
Array.isArray(arr) проверяет, является ли arr массивом.
Методы строк
Чтобы строки корректно работали с методами, в таком случае создаётся
объект - обёртка, а после удаляется.
length — помогает узнать длину строки.
charAt(1) — возвращает символ находящийся в указанной позиции в строке.
toUpperCase — переводит символы строк в верхний регистр.
toLocaleLowerCase — переводит символы строк в нижний регистр.
indexOf — используется для поиска указанного текста в строке, возвращает числовой индекс если указанный символ найден, если нет, то возвращает -1.
lastIndexOf — возвращает последний индекс последнего найденого символа.
Вырезание строк:
slice — возвращает подстроку из строки (исходная строка при этом не изменяется). Первым параметром указывается номер символа строки, с которого начинается вырезание, а вторым параметром — номер символа, на котором закончится вырезание ( символ с этим номером не включится в вырезанную часть).
substring(start, end) — возвращает подстроку строки между двумя индексами, или от одного индекса и до конца строки.
replace — предназначен для замены значений в строке.
trim — отсекает пробельные символы в начале и конце строки.
length — помогает узнать длину строки.
charAt(1) — возвращает символ находящийся в указанной позиции в строке.
toUpperCase — переводит символы строк в верхний регистр.
toLocaleLowerCase — переводит символы строк в нижний регистр.
indexOf — используется для поиска указанного текста в строке, возвращает числовой индекс если указанный символ найден, если нет, то возвращает -1.
lastIndexOf — возвращает последний индекс последнего найденого символа.
Вырезание строк:
slice — возвращает подстроку из строки (исходная строка при этом не изменяется). Первым параметром указывается номер символа строки, с которого начинается вырезание, а вторым параметром — номер символа, на котором закончится вырезание ( символ с этим номером не включится в вырезанную часть).
substring(start, end) — возвращает подстроку строки между двумя индексами, или от одного индекса и до конца строки.
replace — предназначен для замены значений в строке.
trim — отсекает пробельные символы в начале и конце строки.
API / Rest API / Restful API
API — это набор инструментов и протоколов,
которые позволяют различным приложениям взаимодействовать друг с другом.
REST API (Representational State Transfer) — это стиль архитектуры, который определяет правила для создания веб-сервисов.
REST API использует HTTP-протокол для передачи данных и поддерживает операции CRUD (Create, Read, Update, Delete).
Различие между REST API и RESTful API заключается в том, что RESTful API полностью соответствует принципам архитектуры REST, в то время как REST API может не следовать всем правилам и ограничениям.
Таким образом, REST fulAPI является более строгим и эффективным подходом к созданию веб-сервисов, чем просто REST API.
REST API (Representational State Transfer) — это стиль архитектуры, который определяет правила для создания веб-сервисов.
REST API использует HTTP-протокол для передачи данных и поддерживает операции CRUD (Create, Read, Update, Delete).
Различие между REST API и RESTful API заключается в том, что RESTful API полностью соответствует принципам архитектуры REST, в то время как REST API может не следовать всем правилам и ограничениям.
Таким образом, REST fulAPI является более строгим и эффективным подходом к созданию веб-сервисов, чем просто REST API.