Доброго времени суток, друзья!
Представляю вашему вниманию список из второй сотни вопросов по основам JavaScript из этого репозитория с краткими ответами и ссылками на «Современный учебник по JavaScript» Ильи Кантора (JSR) и MDN.
Данный список, а также 300+ практических вопросов доступны в моем приложении.
В приложении реализован механизм запоминания изученного вопроса, а также обеспечена работа в оффлайн-режиме.
Приношу извинения за возможные ошибки и опечатки. Приветствуется любая форма обратной связи.
Редакция от 14.09.
Первые 100 вопросов смотрите здесь.
101. Для чего используется stopPropagation()?
Данный метод используется для предотвращения всплытия или поднятия события вверх по цепочке из предков целевого элемента. Другими словами, он прекращает передачу события от целевого элемента к его предкам. Рассмотрим пример:
<div onclick="f2()">
<div onclick="f1()"></div>
</div>
function f1(event) {
event.stopPropagation()
console.log('Внутренний контейнер')
}
function f2() {
console.log('Внешний контейнер')
}
При клике по вложенному контейнеру в консоль выводится сообщение «Внутренний контейнер». Если убрать event.stopPropagation(), то при клике по вложенному контейнеру, в консоль будут выведены оба сообщения.
JSR
MDN
102. Что делает инструкция return false?
Данная инструкция используется в обработчиках событий для:
- Отмены стандартного поведения браузера
- Предотвращения распространения события по DOM
- Остановки выполнения колбэка и возврата управления вызвавшей его функции
Обратите внимание: без указания возвращаемого значения оператор return возвращает undefined.
JSR
MDN
103. Что такое BOM?
BOM или (Browser Object Model — объектная модель браузера) позволяет JavaScript взаимодействовать с браузером. Данная модель включает в себя такие объекты, как navigator, location, history, screen, XMLHttpRequest и т.п. Другими словами, BOM — это дополнительные объекты, предоставляемые браузером, чтобы работать со всем, кроме документа.
Обратите внимание: BOM не стандартизирована, поэтому ее реализация может отличаться в разных браузерах.
JSR
104. Для чего используется setTimeout()?
Данный метод используется для отложенного выполнения задачи. Другими словами, он позволяет запустить выполнение функции или вычисление выражения через определенное время (в миллисекундах). В следующем примере мы выводим сообщение в консоль через 2 секунды:
setTimeout(() => console.log('Привет!'), 2000)
// во избежание утечек памяти, рекомендуется делать так
const timer = setTimeout(() => {
console.log('Привет!')
clearTimeout(timer)
}, 2000)
JSR
MDN
105. Для чего используется setInterval()?
Данный метод используется для периодического выполнения задачи. Другим словами, он позволяет запускать выполнение функции или вычисление выражения через определенный промежуток времени (в миллисекундах). В следующем примере мы выводим сообщение в консоль каждые 2 секунды:
setInterval(() => console.log('Привет!'), 2000)
// во избежание утечек памяти, не забывайте отключать таймер
// после достижения поставленной цели
let i = 0
const timer = setInterval(() => {
console.log('Привет!')
i++
if (i == 2) {
clearInterval(timer)
}
}, 2000)
Во втором примере сообщение «Привет!» выведется в консоль два раза, после чего таймер будет остановлен
JSR
MDN
106. Почему JavaScript называют однопоточным (single threated)?
JavaScript является однопоточным или синхронным языком программирования. Это означает, что в один момент времени может выполняться только одна задача. Если задача является сложной, ее выполнение может занять продолжительное время и все это время основной поток выполнения кода будет заблокирован. Блокировка потока, в свою очередь, означает отсутствие интерактивности на странице. Браузер перестает реагировать на действия пользователя и другие события. Для решения данной проблемы применяются колбэки, промисы, async/await, воркеры и другие инструменты для работы с асинхронным кодом. В JavaScript в отличие, например, от Java, Go или C++ нет возможности создавать дополнительные потоки или процессы.
JSR
MDN
107. Что такое делегирование событий (event delegation)?
Делегирование событий — это техника, при которой событие регистрируется на родительском элементе для обработки событий, вызываемых дочерними элементами.
Часто применяется для обработки нажатия кнопок в группирующем контейнере или изменения полей для ввода текста в формах, например:
<form>
<input type="text" class="first-input">
<input type="text" class="second-input">
</form>
<div>
<button class="first-button">click</button>
<button class="second-button">click</button>
</div>
const form = document.querySelector('form')
const buttons = document.querySelector('div')
form.addEventListener('input', event => {
console.log(event.target.className)
})
buttons.addEventListener('click', event => {
console.log(event.target.className)
})
В приведенном примере вместо регистрации обработчиков на дочерних элементах, мы регистрируем их на родительских элементах. Ввод текста в поле или нажатие кнопки приводят к выводу названия класса соответствующего элемента в консоль.
JSR
108. Что такое ECMAScript?
ECMAScript — это язык программирования, лежащий в основе JavaScript. Это своего рода шаблон или схема, по которой «строится» JavaScript. ECMAScript стандартизирован в спецификации ECMA-262 организацией по стандартам Ecma International.
JSR
MDN
109. Назовите особенности синтаксиса JSON
Синтаксис JSON имеет следующие особенности:
- Данные представляют собой пары ключ/значение
- Ключ и значение оборачиваются в двойные кавычки, кроме случаев, когда значение является числом («key»: «value»)
- Данные разделяются запятыми
- Объекты оборачиваются в фигурные скобки
- Массивы — в квадратные
JSR
MDN
110. Что делает JSON.stringify()?
При отправке данных на сервер, они должны иметь специальный строковый формат. Для преобразования объекта в строку в формате JSON используется метод JSON.stringify():
const user = { name: 'Ванька', age: 30 }
const str = JSON.stringify(user)
console.log(str) // {"name":"Ванька","age":30}
JSR
MDN
111. Что делает JSON.parse()?
При получении данных от сервера, они имеют специальный строковый формат. Для преобразования этих данных в JavaScript объект используется метод JSON.parse():
const str = { "name":"Ванька","age":30 }
const user = JSON.parse(str)
console.log(user) // {name: "Ванька", age: 30}
JSR
MDN
112. Зачем нужен JSON?
При обмене данными между клиентом и сервером, эти данные могут быть только строками. Поскольку JSON — это текст, он прекрасно для этого подходит. Также он может использоваться как формат для данных любым языком программирования, наряду с другими форматами, такими как XML или Protobuf.
JSR
MDN
113. Что такое PWA (Progressive Web Application — прогрессивное веб-приложение)?
Если кратко, то PWA — это веб-сайты, которые ведут себя подобно нативным приложениям. Они могут быть установлены на телефон или компьютер, а также, как правило, работают в оффлайне. Для последнего используются сервис-воркеры и интерфейс кэширования. Преимуществом PWA перед мобильными приложениями является их размер и относительная легкость разработки. Также не нужно тратить ресурсы на создание двух приложений для одного сайта — веб и мобильного. При этом сохраняется хороший пользовательский опыт.
MDN
114. Для чего используется clearTimeout()?
Данный метод используется для остановки таймера, запущенного с помощью setTimeout(). Для этого идентификатор таймера записывается в переменную, которая затем передается clearTimeout() в качестве аргумента.
const timer = setTimeout(() => {
console.log('Привет!')
clearTimeout(timer)
}, 2000)
В приведенном примере через две секунды в консоль выводится сообщение «Привет!», после чего таймер останавливается. Это делается для того, чтобы сборщик мусора мог удалить выполненный таймер.
JSR
MDN
115. Для чего используется clearInterval()?
Данный метод используется для остановки таймера, запущенного с помощью setInterval(). Для этого идентификатор таймера записывается в переменную, которая затем передается clearInterval() в качестве аргумента.
let i = 1
const timer = setInterval(() => {
console.log(i)
i++
if (i === 3) clearInterval(timer)
}, 1000)
В приведенном примере в консоль каждую секунду выводится значение переменной i, которое каждый раз увеличивается на 1 (1, 2). Когда значение i становится равным 3, таймер останавливается.
JSR
MDN
116. Как выполнить перенаправление?
Для этого можно использовать свойство location объекта window:
location.href = 'newPage.html'
// или
location.replace('newPage.html')
// или
location.assign('newPage.html')
MDN
117. Как проверить, существует ли подстрока в строке?
Существует, как минимум, три способа это сделать.
String.prototype.includes()
const mainStr = 'hello'
const subStr = 'hel'
mainStr.includes(subStr) // true
String.prototype.indexOf()
const mainStr = 'hello'
const subStr = 'hel'
mainStr.indexOf(subStr) !== -1 // true
RegExp
const mainStr = 'hello'
const regex = /hel/
regex.test(mainStr) // true
JSR
MDN — includes
MDN — indexOf
MDN — test
118. Как проверить корректность адреса электронной почты?
Это можно сделать средствами HTML, установив тип поля для ввода в значение email (<input type=«email»>). Однако, данный способ считается не очень надежным. Поэтому, обычно, email валидируется с помощью регулярного выражения. Это рекомендуется делать на стороне сервера, поскольку на клиенте может быть отключен JavaScript:
const validateEmail = email =>
/\S+@\S+.\S+/
.test(email.toString()
.toLowerCase())
const email = 'myemail@example.com'
validateEmail(email) // true
В приведенном примере используется одно из самых простых регулярных выражений для валидации адреса электронной почты. Более надежное выражение выглядит так (RFC 2822): [a-z0-9!#$%&'*+/=?^_\`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?
119. Как получить текущий URL?
Для этого можно использовать свойство location объекта window или свойство URL объекта document:
console.log('Текущий URL', location.href)
console.log('Текущий URL', document.URL) // в Chrome в пустой вкладке получаем "Текущий URL chrome-search://local-ntp/local-ntp.html"
MDN — location
MDN — document.URL
120. Какие свойства имеет объект location?
Свойства объекта location могут использоваться для получения частей URL текущей страницы:
- href — полный URL
- origin — протокол, хост и порт (источник, используется в Политике общего происхождения (SOP) и Совместном использовании ресурсов (CORS))
- protocol
- host — хост и порт
- hostname — хост
- port
- pathname — путь
- search — строка запроса после ?
- hash — строка запроса после # (якоря)
- username — имя пользователя перед доменом
- password — пароль перед доменом
MDN
121. Как получить строку запроса?
Для этого можно использовать конструктор URL:
const url = new URL('https://example.com?foo=1&bar=2')
console.log(url.search) // ?foo=1&bar=2
console.log(url.searchParams.get('foo')) // 1
MDN
122. Как проверить, существует ли свойство в объекте?
Для этого существует, как минимум, три способа.
Оператор in
const user = { name: 'Ванька' }
console.log('name' in user) // true
console.log(!('age' in user)) // true
Метод hasOwnProperty()
const user = { name: 'Ванька' }
console.log(user.hasOwnProperty('name')) // true
console.log(!user.hasOwnProperty('age')) // true
Сравнение с undefined
const user = { name: 'Ванька' }
console.log(user.name !== undefined) // true
console.log(user.age === undefined) // true
JSR
MDN — for...in
MDN — hasOwnProperty
123. Как перебрать перечисляемые свойства объекта?
Для этого можно использовать цикл for...in совместно с методом hasOwnProperty() для исключения унаследованных свойств.
const user = {
name: 'Ванька',
age: 30
}
for (key in user) {
if (user.hasOwnProperty(key)) {
console.log(\`${key}: ${user[key]}\`) // name: Ванька age: 30
}
}
JSR
MDN
124. Как проверить, что объект является пустым?
Для этого существует, как минимум, три способа.
Метод Object.entries()
const obj = {}
console.log(Object.entries(obj).length === 0) // true
// для исключения из проверки объекта Date
const obj2 = new Date()
console.log(Object.entries(obj2).length === 0 && obj2.constructor === Object) // false
Метод Object.keys()
const obj = {}
console.log(Object.keys(obj).length === 0) // true
// для исключения из проверки объекта Date
const obj2 = new Date()
console.log(Object.keys(obj2).length === 0 && obj2.constructor === Object) // false
Цикл for...in и метод Object.hasOwnProperty()
const obj = {}
const obj2 = {key: 'value'}
const isEmpty = obj => {
for (key in obj) {
if (obj.hasOwnProperty(key)) return false
}
return true
}
console.log(isEmpty(obj)) // true
console.log(isEmpty(obj2)) // false
JSR — Объекты
JSR — Object.keys, values, entries
MDN — Object.entries
MDN — Object.keys
MDN — for...in
MDN — Object.hasOwnProperty
125. Что такое объект arguments?
arguments — это массивоподобный объект (псевдомассив), содержащий переданные функции аргументы:
function sum () {
let total = 0
for (let i = 0; i < arguments.length; i++) {
total += arguments[i]
}
return total
// или
let total = 0
for (const i of arguments) {
total += i
}
return total
// или
return Array.from(arguments).reduce((acc, cur) => acc + cur)
}
sum(1, 2, 3) // 6
Обратите внимание, что стрелочные функции не имеют arguments. Вместо arguments рекомендуется использовать оператор rest… (прочие параметры), который работает как в обычных, так и в стрелочных функциях:
const sum = (...rest) => rest.reduce((acc, cur) => acc + cur)
sum(1, 2, 3) // 6
JSR
MDN
126. Как сделать первую букву строки заглавной?
Это можно сделать с помощью методов charAt(), toUpperCase() и slice():
String.prototype.capitilize = function () {
return this.charAt(0).toUpperCase() + this.slice(1)
}
console.log('hello'.capitilize()) // Hello
JSR
MDN — charAt
MDN — toUpperCase
MDN — slice
127. Как получить текущую дату?
Это можно сделать с помощью объекта Date или конструктора Intl.DateTimeFormat:
console.log(new Date().toLocaleDateString()) // 02.09.2020
console.log(new Intl.DateTimeFormat(
'ru-Ru',
{
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric'
}
).format(new Date())) // среда, 2 сентября 2020 г.
JSR — Date
JSR = Intl
MDN — Date
MDN — Intl.DateTimeFormat
128. Как сравнить два объекта Date?
Для этого следует сравнивать не сами объекты, а, например, значения, возвращаемые методом getTime():
const d1 = new Date()
const d2 = new Date(d1)
console.log(d1.getTime() === d2.getTime()) // true
console.log(d1 === d2) // false
JSR
MDN
129. Как проверить, что строка начинается с другой строки?
Для этого можно использовать встроенный метод startsWith():
console.log('Good morning'.startsWith('Good')) // true
console.log('Good morning'.startsWith('morning')) // false
По данным CanIUse данный метод поддерживает почти 94% браузеров
JSR
MDN
130. Как удалить проблемы в строке?
Для этого можно использовать встроенные методы trimStart() (начало строки), trimEnd() (конец строки) и trim() (начало и конец строки):
console.log(' hello world '.trim()) // hello world
trim не работает для пробелов между словами. В этом случае можно воспользоваться методом replace() и регулярным выражением:
console.log('hello world'.replace(/s+/, ' ')) // hello world
// можно уточнить количество пробелов
console.log('hello world'.replace(/s{2,}/, ' ')) // hello world
console.log('key value'.replace(/s{2,}/, ' -> ')) // key -> value
По данным CanIUse методы trimStart() и trimEnd() поддерживает 93% браузеров.
MDN
131. Как добавить новое свойство в объект?
Существует два способа это сделать. Предположим, что у нас есть такой объект:
const obj = {
name: 'Ванька',
age: 30
}
Мы можем добавить в него новое свойство, использую либо точечную, либо скобочную нотацию:
obj.job = 'разработчик'
obj['job'] = 'разработчик'
Одним из отличий указанных методов является то, что при использовании скобочной нотации добавляемый ключ может быть числом:
const obj = {}
obj[1] = 'один'
console.log(obj) // { 1: 'один' }
obj.2 = 'два' // SyntaxError: Unexpected number
JSR
MDN
132. Является ли выражение !-- специальным оператором?
Нет, не является. Это комбинация двух операторов: оператора! (логическое не) и оператора — (декремент). Если использовать указанное выражение с каким-либо значением, то сначала это значение будет уменьшено на единицу, затем преобразовано в логический тип и инвертировано:
const fun = val => !--val
const a = 1
const b = 2
console.log(fun(a)) // !0 -> not false -> true
console.log(fun(b)) // !1 -> not true -> false
JSR
MDN — Logical NOT
MDN — Decrement
133. Как присвоить переменной значение по умолчанию?
Для этого можно использовать оператор || (логическое или):
const a = b || 'default'
В данном случае переменной a будет присвоено значение default в случае, если значение переменной b будет ложным (false, undefined, null, NaN, 0, '').
Если речь идет о стандартных значениях параметров функции, то их можно присвоить следующим образом:
const greet = (name = 'незнакомец') => \`Привет, ${name}!\`
console.log(greet('Ванька')) // Привет, Ванька!
console.log(greet()) // Привет, незнакомец!
Более того, последующие параметры могут использовать значения предыдущих в качестве стандартных значений:
const sum = (a = 1, b = a + 2) => a + b
console.log(sum()) // 4
JSR
MDN
134. Как создать многострочную строку?
Раньше это делали примерно так (конкатенация и управляющие символы переноса строки):
const str =
'Аз есмь' + ' ' +
'очень длинная' + ' ' +
'строка!'
// или
const str = 'Аз есмь a
очень длинная
строка!'
console.log(str)
/*
Аз есмь
очень длинная
строка!
*/
Сейчас это делают так (шаблонный литерал):
const str =
\`Аз есмь
очень длинная
строка!\`
JSR
MDN
135. Можем ли мы добавлять свойства функциям?
Поскольку функции — это тоже объекты, мы вполне можем добавлять им свойства. Значением свойства функции может быть другая функция:
function someFun () {}
someFun.somePropName = 'somePropValue'
console.log(someFun.somePropName) // somePropValue
// дефолтное свойство
console.log(someFun.name) // someFun
const sum = (x, y) => x + y
console.log(sum(1, 2)) // 3
sum.curry = x => y => x + y
console.log(sum.curry(1)(2)) // 3
JSR
MDN
136. Как узнать, сколько аргументов ожидает получить функция?
Для этого можно использовать свойство length:
const sum = (a, b, c) => +a + +b + +c
console.log(sum(1, '1', true)) // 3
console.log(sum(0, '', [])) // 0
console.log(sum.length) // 3
MDN
137. Что такое полифил (polyfill)?
Полифилы используются для обеспечения работы современного JavaScript-кода в старых браузерах. Это делается за счет реализации новых возможностей языка на старом синтаксисе. Сам процесс преобразования нового кода в старый называется транспиляцией. Самым популярным транспилятором JavaScript-кода является Babel.
Например, одной из последних возможностей JavaScript является метод Promise.allSettled(), который, в отличие от Promise.all(), не завершается при отклонении любого из переданных ему промисов.
Однако, на сегодняшний день его поддержка браузерами по данным CanIUse составляет 80%, поэтому нужен полифил:
const promise1 = Promise.resolve('promise1')
const promise2 = Promise.reject('promise2')
const promise3 = Promise.resolve('promise3')
// вот как выглядит встроенный Promise.allSettled()
Promise
.allSettled([promise1, promise2, promise3])
.then(console.log)
/*
[
{status: "fulfilled", value: "promise1"},
{status: "rejected", reason: "promise2"},
{status: "fulfilled", value: "promise3"},
]
*/
// а вот его полифил
// поддержка Promise.all() = 94%
const allSettled = promises => {
const wrappedPromises = promises
.map(p => Promise.resolve(p)
.then(
val => ({
status: 'fulfilled',
value: val
}),
err => ({
status: 'rejected',
reason: err
})))
return Promise.all(wrappedPromises)
}
allSettled([promise1,promise2,promise3])
.then(console.log)
JSR
MDN
138. Для чего используются операторы continue и break?
Оператор break используется для выхода из цикла. После остановки итерации код выполняется дальше:
const obj = {
1: 'Everything',
2: 'is',
3: 'impossible'
}
for (key in obj) {
if (obj[key] === 'impossible') break
console.log(obj[key]) // Everything is
}
console.log('possible') // possible
Оператор continue используется для пропуска итерации:
const obj = {
1: 'Everything',
2: 'is',
3: 'impossible',
4: 'possible'
}
for (key in obj) {
if (obj[key] === 'impossible') continue
console.log(obj[key]) // Everything is possible
}
MDN — break
MDN — continue
139. Что такое метка (label)?
Метки позволяют именовать циклы и блоки кода. Они могут использоваться, например, для выхода из цикла или в качестве условия выполнения кода:
loop1:
for (let i = 0; i < 3; i++) {
loop2:
for (let j = 0; j < 3; j++) {
if (i === j) continue loop1
console.log(\`i = ${i}, j = ${j}\`)
}
}
/*
i = 1, j = 0
i = 2, j = 0
i = 2, j = 1
*/
Использование меток считается плохой практикой.
MDN
140. В чем заключаются преимущества объявления переменных в начале кода?
Рекомендуется объявлять переменные в начала каждого скрипта или фукнции. Это дает следующие преимущества:
- Делает код чистым
- Все переменные находятся в одном месте
- Позволяет избежать случайного создания глобальных переменных
- Предотвращает нежелательное переопределение переменных
JSR
MDN
141. В чем заключаются преимущества инициализации переменной при объявлении?
Рекомендуется инициализировать все переменные в момент объявления. Это дает следующие преимущества:
- Делает код чистым
- Переменные и их значения находятся в одном месте
- Предотвращает присвоение неинициализированным переменным значения undefined
JSR
MDN
142. Назовите основные рекомендации по созданию объекта
Для создания объекта вместо конструктора объекта new Object() рекмондуется использовать скобочную нотацию {}. Также в зависимости от типа значения, рекомендуется использовать следующее:
- строку, например, '' вместо new String()
- число, например, 0 вместо new Number()
- логическое значение, например, false вместо new Boolean()
- [] вместо new Array()
- // вместо new RegExp()
- function (){} вместо new Function()
JSR
MDN
143. Как определить массив в формате JSON?
JSON-массив представляет собой массив JSON-объектов, например:
[
{ "name": "Ванька", "age": 30 },
{ "name": "Петька", "age": 20 }
]
JSR
MDN
144. Как реализовать функцию, возвращающую случайное целое число в заданном диапазоне?
Такую функцию можно реализовать с помощью методов Math.random() и Math.floor() объекта Math:
const getRandomInteger = (min, max) => Math.floor(min + Math.random() * (max + 1 - min))
JSR
MDN — Math.random()
MDN — Math.floor()
145. Что такое tree shaking (встряхивание дерева)?
Tree shaking — это удаление кода неиспользуемых модулей. Такие модули не включаются в окончательную сборку (бандл). Для того, чтобы сборщик модулей (бандлер) мог определить, какие модули используются, а какие нет, структура программы должна быть основана на ES6 модулях. Данная техника была популяризована бандлером Rollup.
MDN
146. Для чего используется tree shaking (встряхивание дерева)?
Tree shaking может существенно уменьшить размер сборки (бандла) за счет удаления из нее кода неиспользуемых модулей. Чем меньше размер сборки, тем выше производительность приложения. Tree shaking реализован в таких сборщиках модулей, как Rollup и Webpack.
MDN
147. Что такое регулярное выражение?
Регулярное выражение — это последовательность символов, формирующая поисковый шаблон. Этот шаблон может использоваться для поиска данных в тексте, например, подстроки в строке. Регулярные выражения широко используются многими языками программирования для операций поиска и замены текста. Общий шаблон регулярного выражения выглядит так:
/шаблон/модификатор
Пример:
const regex = /java/i
const str = 'JavaScript'
console.log(regex.test(str)) // true
Также для создания регулярного выражения можно использовать конструктор RegExp:
const regex = new RegExp('java', 'i')
const str = 'JavaScript'
console.log(regex.test(str)) // true
JSR
MDN
148. Какие методы используются в регулярных выражениях?
В регулярных выражениях используется два основных метода: exec() и test().
Метод exec() ищет совпадение с регулярным выражением в переданной ему в качестве аргумента строке. Поведение данного метода зависит от того, имеет ли регулярное выражение флаг g. Если нет, то возвращается первое совпадение. Если флаг g есть, то:
- Вызов exec() возвращает первое совпадение и запоминает позицию после него в свойстве lastIndex.
- Следующий такой вызов начинает поиск с позиции lastIndex, возвращает следующее совпадение и запоминает позицию после него в lastIndex.
- Если совпадений больше нет, то exec() возвращает null, а для lastIndex устанавливается значение 0.
const str = 'Java и JavaScript - разные языки программирования'
const regex = /Java/g
let result
while (result = regex.exec(str)) {
console.log(
\`Найдено ${result[0]} на позиции ${result.index}\`
)
}
/*
Найдено Java на позиции 0
Найдено Java на позиции 7
*/
Метод test() возвращает логическое значение в зависимости от того, найдено ли совпадение в строке:
const str = 'Я люблю JavaScript'
console.log(
/Я люблю/.test(str) // true
)
JSR
MDN
149. Какие флаги используются в регулярных выражениях?
Флаг | Описание |
---|---|
g | глобальное сопоставление |
i | игнорирование регистра при сопоставлении |
m | сопоставление по нескольким строкам |
const regex = /([а-яё]+)s([а-яё]+)/i
const str = 'Иван Иванов'
const newStr = str.replace(regex, '$2 $1')
console.log(newStr) // Иванов Иван
JSR
MDN
150. Какие специальные символы используются в регулярных выражениях?
Специальные символы, используемые в регулярных выражениях, можно разделить на несколько групп.
Основные символьные классы:
Символ | Значение |
---|---|
\. | любой символ, за некоторым исключением |
\d | цифра |
\D | не цифра |
\w | символ латиницы и нижнее подчеркивание |
\W | не символ латиницы и нижнее подчеркивание |
\s | пробельный символ |
\S | не пробельный символ |
\ | экранирование, например, \. — это точка |
Наборы символов:
Символ | Значение |
---|---|
[а-яёА-ЯЁ] | любая буква русского алфавита |
[^а-яёА-ЯЁ] | любой символ, кроме букв русского алфавита |
Границы:
Символ | Значение |
---|---|
^ | начало строки |
$ | конец строки |
\b | граница слова нулевой ширины |
\B | граница слова ненулевой ширины |
Группировка:
Символ | Значение |
---|---|
(x) | сопоставляется с x, сопоставление запоминается |
(?:x) | сопоставляется с x, сопоставление не запоминается |
Квантификаторы:
Символ | Значение |
---|---|
* | ноль и более символов |
+ | один и более символов |
*? и +? | аналогично * и +, но ищется минимальное совпадение |
? | ноль или один символ |
x(?=y) | сопоставляется с x, если за x следует y |
x(?!y) | сопоставляется с x, если за x не следует y |
(?<=y)x | сопоставляется с x, если x предшествует y |
(?!y)x | сопоставляется с x, если x не предшествует y |
x|y | x или y |
x{n} | n — точное количество x |
x{n,} | n — минимальное количество x |
x{n,m} | n — минимальное количество x, m — максимальное (от, до) |
JSR
MDN
151. Как изменить стили HTML-элемента?
Это можно сделать либо с помощью свойства style, либо присвоив элементу соответствующий класс:
document
.querySelector(selector)
.style.property = value
document
.querySelector('title')
.fontSize = '2rem'
document.querySelector(selector)
.className = 'class-name'
document.querySelector(selector)
.classList.add('class-name')
document.querySelector('button')
.classList.add('active')
JSR
MDN — style
MDN — className
MDN — classList
152. Что такое debugger (отладчик)?
Выражение debugger открывает доступ к любому доступному в конкретном окружении отладочному функционалу, например, к установке контрольных точек (точек останова, брекпойнтов). Если функционал отладки в среде выполнения недоступен, данное выражение не будет иметь никакого эффекта:
const fun = () => {
// магия
debugger // в этом месте выполнение функции будет приостановлено
// магия
}
JSR
MDN
153. Для чего используются контрольные точки debugger (отладчика)?
Контрольные точки используются для приостановки выполнения функции или другого кода в определенном месте с целью выяснения причин неправильной работы программы. После остановки выполнение функции может быть продолжено.
JSR
MDN
154. Можно ли использовать зарезервированные слова в качестве идентификаторов?
Нет, использовать зарезервированные слова в качестве названий переменных, меток, функций или объектов нельзя:
const class = 'Первый раз в первый класс' // SyntaxError: Unexpected token 'class'
155. Как определить ширину и высоту изображения?
Это можно сделать разными способами. Вот один из них:
const getImgSize = src => {
const img = new Image()
img.src = src
img.addEventListener('load', () => console.log(\`${img.width} x ${img.height}\`)) // 276 x 110
document.body.append(img)
}
getImgSize('http://www.google.com/ intl/en_ALL/images/logo.gif')
MDN
156. Как отправить синхронный HTTP-запрос?
Для этого можно использовать объект XMLHttpRequest, передав его методу open() третий опциональный аргумент со значением false:
const getUsers = url => {
const xhr = new XMLHttpRequest()
xhr.open('GET', url, false)
xhr.send()
console.table(xhr.response)
const response = JSON.parse(xhr.response)
const template = \`
<table>
${response.reduce((html, user) => html += \`
<tr>
<td>${user.name}</td>
<td>${user.username}</td>
<td>${user.email}</td>
</tr>\`, '')}
<table>
\`
document.body
.insertAdjacentHTML('beforeend', template)
}
getUsers('https://jsonplaceholder. typicode.com/users')
JSR
MDN
157. Как сделать асинхронный HTTP-запрос?
Для этого можно использовать метод fetch():
const getUsers = async url => {
const response = await fetch(url)
const data = await response.json()
console.table(data)
const template = \`
<table>
${data.reduce((html, user) => html += \`
<tr>
<td>${user.name}</td>
<td>${user.username}</td>
<td>${user.email}</td>
</tr>\`, '')}
<table>
\`
document.body.insertAdjacentHTML('beforeend', template)
}
getUsers('https://jsonplaceholder. typicode.com/users')
JSR
MDN
158. Как получить дату в нужном формате?
Для этого можно использовать метод toLocaleString():
console.log(
new Date().toLocaleString('ru-Ru', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
})
) // воскресенье, 6 сентября 2020 г.
MDN
159. Как получить максимальные размеры страницы?
Для этого нужно найти максимальные значения свойств scrollWidth, offsetWidth, clientWidth и scrollHeight, offsetHeight, clientHeight объектов document.body и document.documentElement:
const pageWidth = Math.max(
document.body.scrollWidth, document.documentElement.scrollWidth,
document.body.offsetWidth, document.documentElement.offsetWidth,
document.body.clientWidth, document.documentElement.clientWidth
)
const pageHeight = Math.max(
document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
document.body.clientHeight, document.documentElement.clientHeight
)
const pageSize = {
width: pageWidth,
heigth: pageHeight
}
console.log(pageSize)
const pageCenter = {
centerX: pageWidth / 2,
centerY: pageHeight / 2
}
console.log(pageCenter)
JSR
160. Что такое условный или тернарный оператор?
Тернарный оператор является сокращенным способом записи блока if...else:
let accesAllowed
const age = propmt('Сколько вам лет?')
// if...else
if (age > 18) {
accesAllowed = true
} else {
accessAllowed = false
}
// тернарный оператор
(age > 18)
? accesAllowed = true
: accessAllowed = false
JSR
MDN
161. Можно ли использовать цепочку из тернарных операторов?
Да, в этом случае тернарный оператор является альтернативой блока if...else if...else:
let accessAllowed
const getAge = () => prompt('Сколько вам лет?')
// это всего лишь пример - не надо так делать
// if...else if...else
const checkAge = (age = getAge()) => {
console.log(age)
if (isNaN(age)) {
Promise.resolve(alert('Возраст должен быть числом')).then(accessAllowed = false).then(checkAge)
} else if (age === null || age === '') {
Promise.resolve(alert('Введите ваш возраст')).then(accessAllowed = false).then(checkAge)
} else if (age < 0) {
Promise.resolve(alert('Возраст не может быть меньше 0')).then(accessAllowed = false).then(checkAge)
} else if (age > 100) {
Promise.resolve(alert('Возраст не может быть больше 100')).then(accessAllowed = false).then(checkAge)
} else if (age < 18) {
Promise.resolve(alert('Извините, вы слишком молоды')).then(accessAllowed = false)
} else {
Promise.resolve(alert('Добро пожаловать!')).then(accessAllowed = true)
}
console.log(accessAllowed)
}
// тернарный оператор
const checkAge = (age = getAge()) => {
isNaN(age)
? Promise.resolve(alert('Возраст должен быть числом')).then(accessAllowed = false).then(checkAge)
: (age === null || age === '')
? Promise.resolve(alert('Введите ваш возраст')).then(accessAllowed = false).then(checkAge)
: (age < 0)
? Promise.resolve(alert('Возраст не может быть меньше 0')).then(accessAllowed = false).then(checkAge)
: (age > 100)
? Promise.resolve(alert('Возраст не может быть больше 100')).then(accessAllowed = false).then(checkAge)
: (age < 18)
? Promise.resolve(alert('Извините, вы слишком молоды')).then(accessAllowed = false)
: Promise.resolve(alert('Добро пожаловать!')).then(accessAllowed = true)
console.log(accessAllowed)
}
JSR
MDN
162. Как начать выполнение кода после полной загрузки страницы?
Это можно сделать несколькими способами.
Разместить тег script перед закрывающим тегом body или добавить ему атрибут defer:
<body>
...
<script src="script.js"></script>
</body>
<!-- или -->
<head>
...
<script src="script.js" defer></script>
</head>
Если ваш скрипт — это модуль, то вместо атрибута defer, нужно указать атрибут type со значением module:
<script src="script.js" type="module"></script>
Добавить тегу body атрибут onload:
<body onload="script()"></body>
Добавить код в качестве обработчика события load объекта window:
window.onload = () => console.log('Страница полностью загружена')
// или
window.addEventListener('load', () => console.log('Страница полностью загружена'))
Сделать тоже самое для document.body:
document.body.onload = () => console.log('Страница полностью загружена')
163. В чем разница между __proto__ и prototype?
Свойство __proto__ (внутреннее скрытое свойство [[Prototype]]) — это объект, от которого экземпляр наследует поля и методы. А prototype — это объект, который используется для создания __proto__ при создании экземпляра с помощью ключевого слова new:
class Person {
constructor(firstName, secondName) {
this.firstName = firstName
this.secondName = secondName
}
getFullName() {
return \`${this.firstName} ${this.secondName}\`
}
}
const user = new Person('Иван', 'Иванов')
console.log(user.getFullName()) // Иван Иванов
console.log(user.__proto__.getFullName === Person.prototype.getFullName) // true
console.log(Person.prototype) // {constructor: ?, getFullName: ?}
console.log(user.prototype === undefined) // true
JSR
MDN
164. Приведите пример обязательного использования точки с запятой
Одним из случаев обязательного использования точки запятой является использование IIFE (Immediately Invoked Fuction Expression — немедленно вызываемого функционального выражения):
Например, следующий код:
try {
const x = 'Быть'
(() => {
console.log(x)
})()
} catch {
console.log('Не быть')
}
Будет интерпретирован так:
try {
const x = 'Быть'(() => {
console.log(x)
})()
} catch {
console.log('Не быть')
}
Поэтому в блоке try мы получаем ошибку TypeError: «Быть» is not a function, управление передается блоку catch, и в консоль выводится «Не быть».
Для того, чтобы код работал, как ожидается, он должен выглядеть так:
try {
// точку с запятой нужно поставить либо здесь
const x = 'Быть';
// либо здесь
;(() => {
console.log(x)
})()
} catch {
console.log('Не быть')
}
Также не забывайте про случаи автоматического расставления точек с запятой.
165. Для чего используется метод freeze()?
Данный метод, как следует из его названия, служит для «замораживания» объекта. Замороженный объект является неизменяемым (иммутабельным). Это означает, что в такой объект нельзя добавлять новые свойства, удалять или изменять существующие. Также этот метод устанавливает configurable: false и writable: false для существующих свойств. Метод возвращает замороженный объект.
'use strict'
const obj = {
mission: 'possible'
}
Object.freeze(obj)
obj.mission = 'impossible' // TypeError: Cannot assign to read only property 'mission' of object '#<Object>'
delete obj.mission // TypeError: Cannot delete property 'mission' of #<Object>
Обратите внимание, что в нестрогом режиме исключение не выбрасывается, код просто не выполняется.
JSR
MDN
166. Зачем нужен метод freeze()?
Парадигма объектно-ориентированного программирования гласит, что интерфейс, содержащий определенное количество элементов, должен быть иммутабельным, т.е. должна быть исключена возможность его расширения, модификации или использования элементов за пределами текущего контекста. Данный метод является алиасом ключевого слова final в некоторых других языках программирования.
JSR
MDN
167. Как сделать первую букву каждого слова в строке заглавной?
Одним из способов это сделать является следующий:
const capitilize = str => str.replace(
/[а-яё]S+/gi,
txt => txt[0].toUpperCase() + txt.slice(1).toLowerCase()
)
console.log(capitilize('аПтека, улИца, фонАрь')) // Аптека, Улица, Фонарь
168. Как узнать, что на странице отключен JavaScript?
Для этого можно использовать тег noscript. Код внутри этого тега будет выполнен только в случае, если на странице отключен JavaScript:
console.log('JavaScript включен')
<noscript>
<p>Включите JavaScript, или ничего не получится</p>
</noscript>
Для того, чтобы отключить JavaScript в Chrome, заходим в настройки -> раздел «Конфиденциальность и безопасность» -> Настройки сайтов -> раздел «Контент» -> JavaScript.
MDN
169. Какие операторы поддерживаются JavaScript?
Операторы служат для работы со значениями или операндами. JavaScript поддерживает следующие операторы:
- Арифметические: + (сложение, приведение к числу, конкатенация), — (вычитание), * (умножение), / (деление), % (деление по модулю, с остатком), ++ (инкремент), — (декремент), ** (возведение в степень)
- операторы сравнения: == (абстрактное, нестрогое равенство), != (абстрактное неравенство), === (строгое равенство, проверка на идентичность), !== (строгое неравенство), >, >=, <, <=
- логические: && (и), || (или),! (не) (!!! (двойное отрицание) не является отдельным оператором)
- операторы присваивания: =, +=, -=, *=, /=, %=
- тернарный: ?...: (if...else)
- оператор typeof: определяет тип операнда
- побитовые: & (и), | (или), ^ (исключающее или), ~ (не), << (левый сдвиг), >> (правый сдвиг), >>> (правый сдвиг с заполнением нулями)
- новые:?.. (опциональная цепочка), ?? (слияние с null)
// опциональная цепочка
const obj = {
foo: {
baz: {
qux: 'bar'
}
}
}
// тогда
console.log(obj.foo.bar.baz.qux) // TypeError: Cannot read property 'baz' of undefined
if (
obj.foo !== undefined &&
obj.foo.bar !== undefined &&
obj.foo.bar.baz !== undefined
) {
console.log(obj.foo.bar.baz.qux) // ошибки не будет
}
// сейчас
console.log(obj?.foo?.bar?.baz?.qux) // undefined
// слияние с null
console.log(
0 || 'default null', // 'default null'
0 ?? 'default null', // 0
'' || 'default string', // default string
'' ?? 'default string', // ''
)
JSR — Операторы
JSR — Логические операторы
JSR — Операторы сравнения
JSR — Условные операторы
JSR — Побитовые операторы
MDN — Оператор опциональной последовательности
MDN — Оператор нулевого слияния
170. Для чего используется оператор rest… (прочие параметры)?
Оператор rest является альтернативой объекта arguments и возвращает массив из переданных функции аргументов:
const sum = (...rest) => rest.reduce((acc, cur) => acc + cur)
console.log(sum(1, 2, 3)) // 6
Обратите внимание, что оператор rest должен передаваться в качестве последнего аргумента:
const fun = (x, ...rest, y) => console.log(rest) // SyntaxError: Rest parameter must be last formal parameter
JSR
MDN
171. Для чего используется оператор spread… (оператор распространения)?
Оператор spread используется для расширения (распаковки, разворачивания) итерируемых сущностей (массивов, строк). Распаковка означает преобразование, например, массива из чисел в набор простых значений:
const sum = (x, y, z) => x + y + z
const nums = [1, 2, 3]
console.log(sum(...nums)) // 6
JSR
MDN
172. Как определить, заморожен ли объект?
Для того, чтобы определить, заморожен ли объект, т.е. является ли он неизменяемым (иммутабельным), используется метод isFrozen():
const obj = {
prop: 'Добро пожаловать в мир JavaScript!'
}
Object.freeze(obj)
console.log(Object.isFrozen(obj)) // true
MDN
173. Как определить равенство значений, используя объект?
Для этого можно использовать метод is():
Object.is('двое из ларца', 'двое из ларца') // true
Object.is(0.1 + 0.2, 0.3) // false
Object.is(window, window) // true
Object.is(+0, -0) // false
const objA = {}
const objB = objA
Object.is(objA, objB) // true
Object.is({}, {}) // false
Значения являются равными, если:
- оба являются undefined
- оба являются null
- оба являются true или false
- оба являются строками одинаковой длины с одинаковыми символами
- оба ссылаются на один объект
- оба являются числами, +0, -0 или NaN
JSR
MDN
174. Как создать копию объекта?
Одним из самых надежных способов это сделать является использование метода assign():
const objA = {a: 1, b: 2}
const objB = Object.assign(objA)
console.log(objB) // {a: 1, b: 2}
console.log(objA === objB) // true
Также данный метод позволяет объединять объекты, исключая дубликаты:
const objA = {a: 1, b: 2}
const objB = {b: 2, c: 3}
const objC = Object.assign(objA, objB)
console.log(objC) {a: 1, b: 2, c: 3}
Для копирования простых объектов можно использовать связку JSON.parse-JSON.stringify:
const objA = {a: 1, b: 2}
const objB = JSON.parse(JSON.stringify(objA))
console.log(objB) // {a: 1, b: 2}
JSR
MDN
175. Что такое прокси?
Объект Proxy «оборачивается» вокруг другого объекта и может перехватывать (и, при желании, самостоятельно обрабатывать) разные действия с ним, например чтение/запись свойств и другие.
const handler = {
get: (obj, prop) => prop in obj
? obj[prop]
: 0
}
// new Proxy(цель, обработчик)
const p = new Proxy({}, handler)
p.a = 1
p.b = true
console.log(p.a, p.b) // 1 true
console.log( 'c' in p, p.c) // false 0
176. Для чего используется метод seal()?
Данный метод «запечатывает» объект, запрещая добавлять/удалять свойства. Он также устанавливает configurable: false для всех существующих свойств. Однако, значения свойств такого объекта можно менять. Для проверки, является ли объект запечатанным, используется метод isSealed().
'use strict'
const obj = {
prop: 'Добро пожаловать в мир JavaScript!'
}
Object.seal(obj)
obj.prop = 'Оставь надежду, всяк сюда входящий'
console.log(Object.isSealed(obj)) // true
delete obj.prop // TypeError: Cannot delete property 'prop' of #<Object>
console.log(obj.prop) // Оставь надежду, всяк сюда входящий
Обратите внимание, что в нестрогом режиме попытка удаления свойства запечатанного объекта тихо завершится ничем.
JSR
MDN
177. В чем разница между методами freeze() и seal()?
Метод Object.seal() в отличие от метода Object.freeze() позволяет изменять существующие свойства объекта.
'use strict'
const objA = {
prop: 'Быть'
}
Object.freeze(objA)
objA.prop = 'Не быть' // TypeError: Cannot assign to read only property 'prop' of object '#<Object>'
const objB = {
prop: 'Не быть'
}
Object.seal(objB)
objB.prop = 'Быть'
console.log(objB.prop) // Быть
178. Как получить перечисляемые пары ключ/значение объекта?
Метод Object.entries() возвращает массив из перечисляемых пар ключ/значение объекта в виде подмассивов в том же порядке, что и цикл for...in:
const obj = {
x: 1,
y: 2
}
console.log(Object.entries(obj)) // [["x", 1], ["y", 2]]
for (let [key, value] of Object.entries(obj)) {
console.log(\`${key}: ${value}\`) // x: 1 y: 2
}
JSR
MDN
179. В чем главное отличие методов Object.keys(), Object.values() и Object.entries()?
Метод Object.keys() возвращает ключи объекта, метод Object.values() — значения его свойств, а Object.entries() массив из пар ключ/значение:
const user = {
name: 'Ванька',
age: 30
}
console.log(Object.keys(user)) // ["name", "age"]
console.log(Object.values(user)) // ["Ванька", 30]
console.log(Object.entries(user)) // [["name", "Ванька"], ["age", 30]]
JSR
MDN — Object.keys()
MDN — Object.values()
MDN — Object.entries()
180. Как создать объект с определенным прототипом, не используя функцию-конструктор и классы?
Для этого можно использовать метод Object.create():
const firstUser = {
name: 'Ванька',
sayHi() {
console.log(\`Привет, меня зовут ${this.name}!\`)
}
}
const secondUser = Object.create(firstUser)
secondUser.name = 'Петька'
secondUser.sayHi() // Привет, меня зовут Петька!
JSR
MDN
181. Для чего используется WeakSet?
WeakSet используется для хранения коллекции объектов со слабыми ссылками. Другими словами, он служит дополнительным хранилищем объектов, используемых другим кодом. Такие объекты автоматически удаляются сборщиком мусора, когда становятся недостижимыми (неиспользуемыми), т.е. когда от объекта остается только ключ в WeakSet.
const ws = new WeakSet()
let user = {}
ws.add(user)
console.log(ws.has(user)) // true
user = null
console.log(ws.has(user)) // false, структура была очищена автоматически
JSR
MDN
182. В чем разница между Set и WeakSet?
Их основным отличием является то, что объекты, хранящиеся в WeakSet, имеют слабые ссылки, т.е. автоматически удаляются, как только становятся недостижимыми. Другие отличия состоят в следующем:
- В Set могут храниться любые значения, а в WeakSet — только объекты
- WeakSet не имеет свойства size
- WeakSet не имеет методов clear(), keys(), values(), forEach()
- WeakSet не является итерируемой сущностью
JSR
MDN
183. Какие методы доступны в WeakSet?
WeakSet обладает следующими методами:
- add(): добавляет объект в коллекцию
- delete(): удаляет объект из коллекции
- has(): определяет наличие объекта в коллекции
- length(): возвращает длину коллекции
const ws = new WeakSet()
const objA = {}
const objB = {}
ws.add(objA)
ws.add(objB)
console.log(ws.has(objA)) // true
console.log(ws.lenghth()) // 2
ws.delete(objA)
console.log(ws.has(objA)) // false
JSR
MDN
184. Для чего используется WeakMap?
WeakMap используется для хранения пар ключ/значение, в которых ключи имеют слабые ссылки. Другими словами, он служит дополнительным хранилищем ключей, используемых другим кодом. Такие ключи автоматически удаляются сборщиком мусора, когда становятся недостижимыми (неиспользуемыми), т.е. когда от них остается только ключ в WeakMap.
const wm = new WeakMap()
let user = {}
wm.set(user, 'user')
console.log(wm.has(user)) // true
user = null
console.log(wm.has(user)) // false, структура была очищена автоматически
JSR
MDN
185. В чем разница между Map и WeakMap?
Их основным отличием является то, что ключи, хранящиеся в WeakMap, имеют слабые ссылки, т.е. автоматически удаляются как только становятся недостижимыми. Другие отличия состоят в следующем:
- В Map в качестве ключей могут использоваться любые значения, а в WeakMap — только объекты
- WeakMap не имеет свойства size
- WeakMap не имеет методов clear(), keys(), values(), entries(), forEach()
- WeakMap не является итерируемой сущностью
JSR
MDN
186. Какие методы доступны в WeakMap?
WeakMap обладает следующими методами:
- set(): добавляет пару ключ/значение в объект
- delete(): удаляет значение по ключу
- has(): определяет наличие значения по ключу
- get(): возвращает значение по ключу
const wm = new WeakMap()
const firstUser = {}
const secondUser = {}
wm.set(firstUser, 'Ванька')
wm.set(secondUser, 'Петька')
console.log(wm.has(firstUser)) // true
console.log(wm.get(firstUser)) // Ванька
wm.delete(secondUser)
console.log(wm.has(secondUser)) // false
JSR
MDN
187. Как закодировать URL?
Для этого можно использовать метод encodeURI(). Данный метод преобразует все специальные символы, кроме, /?: @ = + $ #
const url = 'https://ru.wikipedia.org/wiki/Лермонтов,_Михаил_Юрьевич'
const encoded = encodeURI(url)
console.log(encoded) // https://ru.wikipedia.org/wiki/%D0%9B%D0...
JSR
MDN
188. Как раскодировать URL?
Для этого можно использовать метод decodeURI():
const url = 'https://ru.wikipedia.org/wiki/%D0%9B%D0...'
const decoded = decodeURI(url)
console.log(decoded) // https://ru.wikipedia.org/wiki/Лермонтов,_Михаил_Юрьевич
JSR
MDN
189. Как вывести содержимое страницы на печать?
Для этого можно использовать глобальный метод print(). Данный метод открывает специальное диалоговое окно с настройками печати:
<button>Печать</button>
document.querySelector('button')
.addEventListener('click', () => print())
MDN
190. Что такое анонимная функция?
Анонимная функция — это функция без названия. Такие функции часто присваиваются переменным, а также используются в качестве колбэков:
const sayHi = function () {
console.log('Привет')
}
sayHi() // Привет
// или
const sayBye = () => console.log('Пока')
sayBye() // Пока
window.addEventListener('click', function () {
console.log('Не буди лихо, пока оно тихо')
})
// или
window.addEventListener('contextmenu', e => {
e.preventDefault()
console.log('Контекстное меню - детям не игрушка')
})
JSR
MDN
191. Каков приоритет использования локальных и глобальных переменных?
Локальные переменные имеют приоритет над одноименными глобальными переменными:
let question = 'Не быть'
function toBe () {
question = 'Быть'
console.log(question)
}
toBe() // Быть
JSR
MDN
192. Что такое аксессоры?
Аксессоры или вычисляемые свойства — это геттеры и сеттеры. Геттеры используются для получения значений свойств объекта, а сеттеры — для их установки:
class User {
constructor (name, age) {
this.name = name
this.age = age
}
#access = false
get access () {
return this.#access
}
set access (bool) {
this.#access = bool
}
}
const user = new User('Ванька', 30)
console.log(user.#access) // SyntaxError: Private field '#access' must be declared in an enclosing class
console.log(user.access) // false
user.access = true
console.log(user.access) // true
Геттеры и сеттеры — это свойства, а методы — функции:
class User {
constructor (name, age) {
this.name = name
this.age = age
}
#access = false
getAccess () {
return this.#access
}
setAccess(bool) {
this.#access = bool
}
}
const user = new User('Ванька', 30)
console.log(user.#access) // SyntaxError: Private field '#access' must be declared in an enclosing class
console.log(user.getAccess()) // false
user.setAccess(true)
console.log(user.getAccess()) // true
JSR
193. Как определить свойство в конструкторе объекта?
Для этого можно использовать метод Object.defineProperty(). Данный метод позволяет добавлять новые свойства к объекту и модифицировать существующие, а также изменять настройки доступа к объекту:
'use strict'
const obj = {}
Object.defineProperty(obj, 'prop', {
value: 1,
writable: false
})
console.log(obj.prop) // 1
obj.prop = 2 // TypeError: Cannot assign to read only property 'prop' of object '#<Object>'
В нестрогом режиме попытка изменить свойство только для чтения тихо завершится ничем.
JSR
MDN
194. В чем заключаются особенности геттеров и сеттеров?
Основными особенностями геттеров и сеттеров является следующее:
- Они имеют более простой по сравнению с методами синтаксис
- Используются для определения вычисляемых свойств — аксессоров
- Позволяют обеспечить одинаковые отношения между свойствами и методами
- Могут обеспечивать более высокое качество данных
- Позволяют выполнять задачи за сценой, когда речь идет об инкапсуляции
JSR
195. Можно ли добавить к объекту геттеры и сеттеры с помощью метода Object.defineProperty()?
Вполне:
const obj = {counter: 0}
Object.defineProperty(obj, 'increment', {
get() {return ++this.counter}
})
Object.defineProperty(obj, 'decrement', {
get() {return --this.counter}
})
Object.defineProperty(obj, 'sum', {
set(val) {return this.counter += val}
})
Object.defineProperty(obj, 'sub', {
set(val) {return this.counter -= val}
})
obj.sum = 10
obj.sub = 5
console.log(obj) // {counter: 5}
console.log(obj.increment) // 6
console.log(obj.decrement) // 5
JSR
MDN
196. Для чего используется switch...case?
switch...case является альтернативой if...else и представляет собой более наглядный способ выполнения кода в зависимости от переданного условия:
const calc = (x, y, operator) => {
let result
try {
switch (operator) {
case '+':
result = x + y
break
case '-':
result = x - y
break
case '*':
result = x * y
break
case '/':
result = x / y
break
default:
throw new Error('Некорректная операция')
}
if (isNaN(result)) {
throw new Error('Операнды должны быть числами')
}
console.log(result)
return result
} catch (e) {
console.error(e.message)
}
}
calc(1, 2, '+') // 3
calc(3, 4, '*') // 12
calc('a', 1, '-') // Операнды должны быть числами
calc(5, 6, 'x') // Некорректная операция
JSR
MDN
197. Назовите правила использования switch...case
При использовании конструкции switch...case необходимо придерживаться следующих правил:
- условие может быть числом или строкой
- не допускается дублирование значений
- инструкция default является опциональной. Если ни для одного блока case не найдено совпадения, выполняется блок default
- break используется для остановки цикла
- break также является опциональным, но без него выполнение цикла продолжится
JSR
MDN
198. Назовите примитивные типы данных.
Примитивными типами данных («примитивами») в JavaScript являются следующие значения:
- number для любых чисел: целочисленных или чисел с плавающей точкой, целочисленные значения ограничены диапазоном ±253
- bigint для целых чисел произвольной длины
- string для строк. Строка может содержать один или больше символов, нет отдельного символьного типа
- boolean для true/false
- null для неизвестных значений – отдельный тип, имеющий одно значение null
- undefined для неприсвоенных значений – отдельный тип, имеющий одно значение undefined
- symbol для уникальных идентификаторов
MDN
Дополнительная литература
Habr — Из чего сделан JavaScript?
Habr — Зачем в JavaScript нужен строгий режим?
Насколько JavaScript сильный?
Medium — Advanced JavaScript ES6 — Temporal Dead Zone, Default Parameters And Let vs Var — Deep dive!
JavaScript: область видимости простыми словами
Делегирование событии? в JavaScript
Medium — Понимаем замыкания в JavaScript. Раз и навсегда
Habr — Дэн Абрамов о замыканиях в JavaScript
Medium — Understanding Prototypes in JavaScript
Medium — Подробно о методах apply(), call() и bind(), необходимых каждому JavaScript разработчику
JavaScript: полное руководство по классам
Medium — JavaScript Classes: An In-Depth look (Part 1)
Medium — Разбираемся с путаницей между JavaScript методами slice(), splice() и split()
Копирование объектов в JavaScript
Начало работы с методами JavaScript-массивов .map(), .filter() и .reduce()
Как работает reduce() в JavaScript
Работаем с асинхроннои? итерациеи? в ECMAScript 2019, используя for-of
Новшества ES2020, которые мне очень нравятся
DigitalOcean — Знакомство с объектами map и set в JavaScript
Medium — Понимаем каррирование в JavaScript
Medium — What is Memoization in Javascript?
Redd — Debounce vs Throttle: Definitive Visual Guide
Путь к пониманию шаблонных литералов в JavaScript
Habr — 5 малоизвестных возможностей JSON.stringify()
Habr — Понимание (всех) «модульных» форматов и инструментов JavaScript
Habr — Использование JavaScript-модулей в продакшне: современное состояние дел. Часть 1
Habr — Визуализация работы сервис-воркеров
GoogleDevelopers — Service Workers: an Introduction
Habr — Хранилище для веба
WebDevBlog — Изучаем IndexedDB
GoogleDevelopers — Working with IndexedDB
Habr — Web Storage API: примеры использования
Habr — Прослушиватели событий и веб-воркеры
Medium — A Simple Introduction to Web Workers in JavaScript
Habr — Распространенные ошибки при работе с промисами в JavaScript, о которых должен знать каждый
Habr — Визуализация промисов и Async/Await
Habr — Политика общего происхождения и CORS: визуальное руководство
borshak
Аж рука листать устала… Чтобы оценить, насколько человек понимает JS, достаточно попросить рассказать о замыканиях, event loop и контексте выполнения функции.