Доброго времени суток, друзья!

Представляю вашему вниманию список из первых 100 вопросов по основам JavaScript из этого репозитория с краткими ответами и ссылками на «Современный учебник по JavaScript» Ильи Кантора (JSR) и MDN. Также в конце имеются ссылки на статьи для пытливых умов.

Данный список, а также 300+ практических вопросов доступны в моем приложении, которое можно посмотреть и установить здесь (PWA Store) и здесь (Netlify). В приложении реализован механизм запоминания изученного вопроса, а также обеспечена работа в офлайн-режиме.

Приношу извинения за возможные ошибки и опечатки. При их обнаружении, не стесняйтесь писать в личку, буду весьма признателен.

Список вопросов:
Как создать объект?
Что такое прототипы?
В чем разница между Call, Apply и Bind?
Что такое JSON и какие у него есть методы?
Что делает метод Array.slice()?
Что делает метод Array.splice()?
В чем разница между slice() и splice()?
Как сравниваются объекты (objects) и карты (maps)?
В чем разница между операторами "==" и "==="?
Что такое лямбда- или стрелочные функции?
Почему функции называют объектами первого класса?
Что такое функция первого порядка?
Что такое функция высшего порядка?
Что такое унарная функция?
Что такое каррирование (currying)?
Что такое чистая функция?
Для чего используется ключевое слово «let»?
В чем разница между let и var?
Почему в качестве ключевого слова было выбрано слово «let»?
Как переопределить переменную в блоке switch?
Что такое временная мертвая зона?
Что такое немедленно вызываемое функциональное выражение (IIFE, Immediately Invoked Function Expression)?
В чем заключаются преимущества использования модулей?
Что такое запоминание или мемоизация?
Что такое поднятие переменных (hoisting)?
Что такое класс?
Что такое замыкание?
Что такое модуль?
Зачем нужны модули?
Что такое область видимости?
Что такое сервис-воркер (service worker)?
Как взаимодействовать с объектной моделью документа (Document Object Model, DOM) с помощью сервис-воркеров?
Как повторно использовать информацию при перезапуске сервис-воркера?
Что такое индексированная база данных (IndexedDB)?
Что такое веб-хранилище (Web Storage)?
Что такое postMessage?
Что такое куки (cookie)?
Зачем нужны куки?
Какими возможностями обладают куки?
Как удалить куки?
В чем разница между куки, локальным и сессионным хранилищами?
В чем главное отличие между локальным и сессионным хранилищами?
Как получить доступ к веб-хранилищу?
Какие методы предоставляет сессионное хранилище?
Какое событие возникает при работе с веб-хранилищем?
Для чего используется веб-хранилище?
Как определить поддержку веб-хранилища браузером?
Как определить поддержку сервис-воркеров браузером?
Приведите пример веб-воркера
Назовите ограничения веб-воркеров по работе с DOM
Что такое промис (обещание, promise)?
Зачем нужны промисы?
Назовите три возможных состояния промиса
Что такое функция обратного вызова (колбек)?
Зачем нужны колбеки?
Что такое ад колбеков?
Что такое события, отправленные сервером (server-sent events, SSE)?
Как получать сообщения (уведомления или события), отправленные сервером?
Как проверить поддержку SSE браузером?
Какие события возникают при работе с SSE?
Назовите основные правила работы с промисами
Что такое колбек в колбеке?
Что такое цепочка из промисов?
Что такое Promise.all()?
Что такое Promise.race()?
Что такое строгий режим?
Зачем нужен строгий режим?
Как включить строгий режим?
Для чего используется двойное отрицание?
Для чего используется оператор «delete»?
Для чего используется оператор «typeof»?
Что такое undefined?
Что такое null?
В чем разница между null и undefined?
Что такое eval?
В чем разница между window и document?
Как получить доступ к истории браузера?
Какие типы данных существуют в JavaScript?
Что делает isNaN()?
В чем разница между необъявленными и неопределенными переменными?
Что такое глобальные переменные?
Какие проблемы влечет за собой создание глобальных переменных?
Что такое NaN?
Что делает isFinite()?
Что такое поток событий (event flow)?
Что такое всплытие события?
Что такое погружение или захват события?
Как отправить форму на обработку?
Как получить информацию об операционной системе?
В чем разница между событиями «DOMContentLoaded» и «load»?
В чем разница между нативными, хостовыми (принадлежащими среде выполнения кода) и пользовательскими объектами?
Какие средства используются для откладки кода?
В чем заключаются преимущества и недостатки промисов по сравнению с колбеками?
В чем разница между атрибутом и свойством элемента?
Что такое политика общего происхождения (same-origin policy)?
Что делает void 0?
JavaScript — это компилируемый или интерпретируемый язык программирования?
Чувствителен ли JavaScript к регистру?
Связаны ли Java и JavaScript?
Что такое событие (event)?

Дополнительная литература

Как создать объект?


Существует множество способов это сделать. Вот некоторые из них:

Конструктор объекта

Один из способов заключается в использовании конструктора объекта.

const object = new Object()

Метод Object.create()

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

const object = Object.create(null)

Литерал объекта

Синтаксис объектного литерала эквивалентен методу Object.create().

const object = {}

Функция-конструктор

Создаем функцию-конструктор и применяем оператор «new» для создания экземпляра этой функции — объекта.

function Person (name) {
    const object = { }
    object.name = name
    object.age = 30
    return object
}
const object = new Person('John')

Функция-конструктор и прототип

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

function Person ( ) { }
Person.prototype.name = 'John'
const object = new Person()

Это похоже на создание экземпляра с помощью Object.create() с прототипом функции и привязку данной функции к экземпляру с параметрами в качестве аргументов.

function f {}
new f(x, y, z)

Или:

// создаем новый экземпляр, используя прототип функции
const newInstance = Object.create(f.prototype)
// привязываем функцию
const result = f.call(newInstance, x, y, z)
// если result не нулевой объект, используем ее, иначе, используем newInstance
console.log(result && typeof result === 'object' ? result : newInstance)

Класс

Для создания объектов могут использоваться классы.

class Person {
    constructor(name) {
        this.name = name
    }
}
const object = new Person('John')

JSR
MDN

Что такое прототипы?


Прототипы используется для создания новых объектов на основе существующих. Такая техника называется прототипным наследованием. Прототип экземпляра объекта доступен через Object.getPrototypeOf(object) или свойство __proto__ (внутреннее скрытое свойство [[Prototype]]), а прототип функции-конструктора доступен через Object.prototype.



JSR
MDN

В чем разница между Call, Apply и Bind?


Разницу между данными методами можно объяснить с помощью следующих примеров.
Метод call() вызывает функцию с указанным значением this и аргументами через запятую.

const employee1 = { firstName: 'Иван', lastName: 'Иванов' }
const employee2 = { firstName: 'Петр', lastName: 'Петров' }
function invite (greet1, greet2) {
    console.log(`${greet1}, ${this.firstName} ${this.lastName}. ${greet2}`)
}
invite.call(employee1, 'Привет', 'Как дела?') // Привет, Иван Иванов. Как дела?
invite.call(employee2, 'Привет', 'Как дела?') // Привет, Петр Петров. Как дела?

Метод apply() вызывает функцию с указанным значением this и аргументами в виде массива.

const employee1 = { firstName: 'Иван', lastName: 'Иванов' }
const employee2 = { firstName: 'Петр', lastName: 'Петров' }
function invite (greet1, greet2) {
    console.log(`${greet1}, ${this.firstName} ${this.lastName}. ${greet2}`)
}
invite.apply(employee1, ['Привет', 'Как дела?']) // Привет, Иван Иванов. Как дела?
invite.apply(employee2, ['Привет', 'Как дела?']) // Привет, Петр Петров. Как дела?

Метод bind() возвращает новую функцию с указанным значением this и позволяет передать ей массив или любое количество аргументов через запятую.

const employee1 = { firstName: 'Иван', lastName: 'Иванов' }
const employee2 = { firstName: 'Петр', lastName: 'Петров' }
function invite (greet1, greet2) {
    console.log(`${greet1}, ${this.firstName} ${this.lastName}. ${greet2}`)
}
const inviteEmployee1 = invite.bind(employee1)
const inviteEmployee2 = invite.bind(employee2)
inviteEmployee1('Привет', 'Как дела?') // Привет, Иван Иванов. Как дела?
inviteEmployee2('Привет', 'Как дела?') // Привет, Петр Петров. Как дела?

Таким образом, методы call() и apply() вызывают функцию после ее привязки к объекту. Разница между ними состоит в способе передачи аргументов. Эту разницу легко запомнить при помощи первых букв методов: call — это запятая (comma, c), apply — массив (array, a). Метод bind() возвращает новую функцию, привязанную к указаному объекту.

JSR — Call/Apply
JSR — Bind
MDN — Call
MDN — Apply
MDN — Bind

Что такое JSON и какие у него есть методы?


JSON — это текстовый формат данных, основанный на синтаксисе объектов JavaScript, изобретенный Дугласом Крокфордом. Он используется для передачи данных по сети и, обычно, имеет расширение .json и MIME-тип application/json.

Разбор (парсинг): преобразует строку в формате JSON в объект.

JSON.parse(text)

Стрингификация: преобразует объект в строку в формате JSON для передачи по сети.

JSON.stringify(object)

JSR
MDN

Что делает метод Array.slice()?


Метод slice() возвращает выбранные элементы массива в виде нового массива. Он возвращает элементы, начиная с индекса, указанного в первом аргументе, и заканчивая, но не включая, индексом, указанном во втором необязательном аргументе. Если второй аргумент отсутствует, то будут извлечены все элементы, начиная с индекса, указанного в первом аргументе.

const arrayIntegers = [1, 2, 3, 4, 5]
const arrayIntegers1 = arrayIntegers.slice(0, 2) // [1, 2]
const arrayIntegers2 = arrayIntegers.slice(2, 3) // [3]
const arrayIntegers3 = arrayIntegers.slice(4) // [5]

Обратите внимание, что данный метод не изменяет исходный массив, а лишь возвращает его подмножество в виде нового массива.

JSR
MDN

Что делает метод Array.splice()?


Метод splice() используется для добавления или удаления элементов в или из массива. Первый аргумент определяет начальную позицию для добавления или удаления элементов, второй опциональный аргумент — количество удаляемых элементов. Каждый последующий аргумент добавляется в массив:

let arrayOriginal1 = [1, 2, 3, 4, 5]
let arrayOriginal2 = [1, 2, 3, 4, 5]
let arrayOriginal3 = [1, 2, 3, 4, 5]
let array1 = arrayOriginal1.splice(0, 2) // возвращается [1, 2]; исходный массив = [3, 4, 5]
let array2 = arrayOriginal2.slice(3) // возвращается [4, 5]; исходный массив = [1, 2, 3]
let array3 = arrayOriginal3.slice(3, 1, 'a', 'b', 'c') // возвращается [4]; исходный массив = [1, 2, 3, 'a', 'b', 'c']

Обратите внимание, что метод splice() модифицирует исходный массив и возвращает массив извлеченных элементов.

JSR
MDN

В чем разница между slice() и splice()?


Главные отличия состоят в следующем:
Slice Splice
Не изменяет исходный массив Изменяет исходный массив
Возвращает подмассив исходного массива Возвращает удаленные элементы в виде массива
Служит для извлечения элементов из массива Служит для добавления/удаления элементов в/из массива

JSR
MDN — Slice
MDN — Splice

Как сравниваются объекты (objects) и карты (maps)?


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

  • Ключами объекта могут быть только строки и символы, а ключами карты — любые значения, включая функции и объекты
  • Ключи карты упорядочены, а ключи объекта нет. Поэтому при итерации ключи карты возвращаются в порядке их добавления
  • Вы можете получить размер карты с помощью свойства size, а количество свойств объекта определяется вручную
  • Карта является итерируемой сущностью, т.е. перебираемой по умолчанию, а для итерации по объекту необходимо сначала каким-то образом получить его ключи, а затем их перебрать
  • При использовании объекта в качестве карты следует помнить о том, что любой объект имеет прототип, поэтому собственные ключи такой карты могут пересекаться с вашими ключами. Поэтому для создания карты-объекта следует использовать Object.create(null), но сейчас такой способ используется крайне редко
  • Объект уступает карте в плане производительности, когда речь идет о быстром добавлении/удалении ключей

JSR
MDN

В чем разница между операторами "==" и "==="?


JavaScript предоставляет два способа для сравнения значений: строгое (===, !==) и абстрактное (==, !==). При строгом сравнении значения сравниваются как есть, а при нестрогом при необходимости осуществляется неявное преобразование (приведение) типов значений. Строгие операторы используют следующие правила для сравнения различных типов значений:

  • Две строки являются строго равными, когда они имеют одинаковый набор символов, одинаковую длину и одинаковые символы на одних и тех же позициях
  • Два числа являются строго равными, если равны их значения. Существует два особых случая:

    • NaN не равно ничему, включая NaN
    • Положительный и отрицательный нули равны друг другу

Логические значение являются строго равными, когда оба являются истинными или ложными, т.е. true или false
Два объекта являются строго равными, если ссылаются на один и тот же объект (место в памяти)
null === undefined возвращает false, но null == undefined возвращает true

Несколько примеров:

0 == false // true
0 === false // false
1 == "1" // true
1 === "1" // false
null == undefined // true
null === undefined // false
'0' == false // true
'0' === false // false
[] == [] // или
[] === [] // false, ссылаются на разные места в памяти
{} == {} // или
{} === {} // false, ссылаются на разные места в памяти

JSR
MDN

Что такое лямбда- или стрелочные функции?


Стрелочные функции — это сокращенный способ записи функциональных выражений. Они не имеют собственных this, arguments, super и new.target. Эти функции служат хорошей альтернативой функциям, не имеющим методов, но не могут использоваться как конструкторы.

JSR
MDN

Почему функции называют объектами первого класса?


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

const handler = () => console.log('Это функция обработки клика')
document.addEventListener('click', handler)

JSR
MDN

Что такое функция первого порядка?


Функция первого порядка — это функция, которая не принимает другую функцию в качестве аргумента и не возвращает функцию как значение:

const firstOrder = () => console.log('Я - функция первого порядка')

JSR
MDN

Что такое функция высшего порядка?


Функция высшего порядка — это функция, которая принимает другую функцию в качестве аргумента или возвращает другую функцию как значение:

const firstOrderFunc = () => console.log('Я - функция первого порядка')
const higherOrder = returnFirstOrderFunc => returnFirstOrderFunc()
higherOrder(firstOrderFunc)

JSR
MDN

Что такое унарная функция?


Унарная функция (функция-монада) — это функция, принимающая только один аргумент:

const unaryFunction = a => console.log(a + 10) // прибавляем 10 к переданному аргументу и выводим результат в консоль

JSR
MDN

Что такое каррирование (currying)?


Каррирование — это процесс преобразования функции с несколькими параметрами в несколько функций с одним параметром. Данный процесс назван в четь математика Хаскелла Карри. Каррирование превращает одну n-арную функцию в несколько унарных функций (уменьшает арность функции):

const multiArgF = (a, b, c) => a + b + c
const curryUnaryF = a => b => c => a + b + c
curryUnaryF(1) // возвращает функцию: b => c => 1 + b + c
curryUnaryF(1)(2) // возвращает функцию: c => 3 + c
curryUnaryF(1)(2)(3) // возвращает число 6

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

JSR

Что такое чистая функция?


Чистая функция — это функция, возвращаемое значение которой зависит только от передаваемых аргументов, без побочных эффектов. Проще говоря, если вы вызывается функцию n раз с n аргументами, и функция всегда возвращает одно и тоже значение, значит, она является чистой:

// не чистая
let numberArray = []
const impureAddNumber = number => numberArray.push(number)
// чистая
const pureAddNumber = number => argNumberArray => argNumberArray.concat([number])
// отображаем результаты
console.log(impureAddNumber(6)) // 1
console.log(numberArray) // [6]
console.log(pureAddNumber(7)(numberArray)) // [6, 7]
console.log(numberArray) // [6]

В приведенном примере impureAddNumber не является чистой функцией, поскольку метод push() возвращает новую длину массива, которая не зависит от передаваемого аргумента. Вторая функция является чистой, поскольку метод concat() объединяет два массива без побочных эффектов и возвращает новый массив. Чистые функции важны для юнит-тестирования и не нуждаются во внедрении зависимостей. Отсутствие побочных эффектов повышает надежность приложения за счет более слабых связей между его элементами. Одним из воплощений данного принципа является концепция неизменности (иммутабельности), представленная в ES6, и заключающаяся в предпочтении const перед let.

JSR
MDN

Для чего используется ключевое слово «let»?


Ключевое слово «let» служит для объявления локальной переменной, имеющей блочную область видимости. Область видимости такой переменной органичена блоком, оператором или выражением, в котором она используется. Переменные, объявленные с помощью ключевого слова «var», имеют глобальную область видимости или область видимости функции, в которой они определены:

let counter = 30
if (counter === 30) {
let counter = 31
    console.log(counter) // 31
}
console.log(counter) // 30 (переменная counter, объявленная в блоке, здесь не существует)

JSR
MDN

В чем разница между let и var?


Основные отличия состоят в следующем:
var let
Доступно с момента появления JavaScript Представлено в ES6
Имеет глобальную или функциональную область видимости Имеет блочную область видимости
Переменные поднимаются в начало области видимости Переменные также поднимаются, но не инициализируются (поднимается только объявление, но не присвоение значения)

Несколько примеров:

function userDetails(username) {
    if (username) {
        console.log(salary)
        console.log(age)
        let age = 30
        var salary = 10000
    }
    console.log(salary) // 10000 (область видимости функции)
    console.log(age) // ошибка: age не определена (блочная область видимости)
}

JSR
MDN — let
MDN — var

Почему в качестве ключевого слова было выбрано слово «let»?


Let (пусть) — это математический оператор, который использовался ранними языками программирования, такими как Scheme и Basic. В настоящее время let используется большим количеством языков программирования, так что данное слово является наиболее близкой альтернативой сокращению «var» (variable — переменная).
JSR
MDN

Как переопределить переменную в блоке switch?


Если вы попытаетесь переопределить переменную, объявленную с помощью ключевого слова «let» в блоке switch, то получите ошибку:

let counter = 1
switch(x) {
    case 0:
        let name
        break
    case 1:
        let name // синтаксическая ошибка (SyntaxError)
        break
}

Для решения данной задачи необходимо создать новый блок внутри case — новую лексическую область видимости:

let counter = 1
switch(x) {
    case 0: {
        let name
        break
    }
    case 1: {
        let name
        break
    }
}

JSR
MDN

Что такое временная мертвая зона?


При попытке доступа к переменным, объявленным с помощью ключевого слова «let» или «const» (но не «var»), до их определения (т.е. до присваивания им значения внутри текущей области видимости) будет выброшено исключение ReferenceError (ошибка ссылки). Другими словами, временной мертвой зоной называется время между созданием контекста (области видимости) переменной и ее определением:

function someMethod () {
    console.log(counter1) // undefined
    console.log(counter2) // ReferenceError
    var counter1 = 1
    const counter2 = 2
}

MDN

Что такое немедленно вызываемое функциональное выражение (IIFE, Immediately Invoked Function Expression)?


IIFE — это функция, которая вызывается сразу после определения. Синтаксис такой функции может выглядеть так (один из вариантов, наиболее распространенный):

(function () {
    // код
})()
// или, если речь идет о стрелочной функции
(() => {
    // код
})()

Главная причина использования IIFE заключается в обеспечении приватности переменных, поскольку доступ к переменным, объявленным внутри IIFE, нельзя получить из внешнего окружения:

(function () {
    var message = 'IIFE'
    console.log(message)
})()
console.log(message) // ошибка: message не определена

JSR
MDN

В чем заключаются преимущества использования модулей?


Среди прочего, можно назвать следующее:

  • Повышение читаемости и облегчение поддержки кода
  • Возможность повторного использования кода
  • Сохранение чистоты глобального пространства имен

JSR
MDN

Что такое запоминание или мемоизация?


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

const memoizAddition = () => {
    let cache = {}
    return value => {
        if (value in cache) {
            console.log('Получение данных из кэша')
            return cache[value] // в данном случае, cache.value не может быть использовано в качестве названия свойства, поскольку названия свойств в JS не могут начинаться с числа. Поэтому используется скобочная нотация
        } else {
            console.log('Результат вычисляется')
            let result = value + 20
            cache[value] = result
            return result
        }
    }
}
// возвращаем функцию из memoizAddition
const addition = memoizAddition()
console.log(addition(20)) // Результат вычисляется 40
console.log(addition(20)) // Получения данных из кэша 40

Что такое поднятие переменных (hoisting)?


Поднятие — это процесс перемещения переменных и функциональных выражений в начало их области видимости перед выполнением кода. Запомните: поднимаются только сами переменные и выражения, а не их инициализация (т.е. поднимается объявление переменной, а не присваивание ей значения):

console.log(message) // undefined
var message = 'Хойстинг'

Для компилятора данный код выглядит так:

var message
console.log(message)
message = 'Хойстинг'

JSR
MDN

Что такое класс?


Классы, представленные в ES6, являются синтаксическим сахаром (оберткой, абстракцией или надстройкой) для прототипного наследования (для прототипа функции-конструктора). Пример функции-конструктора:

function Bike(model, color) {
    this.model = model
    this.color = color
}
Bike.prototype.getDetails = function () {
    return 'Эта ' + this.model + ' велосипеда имеет ' + this.color + ' цвет.'
}

Тот же пример с использованием класса:

class Bike {
    constructor (color, model) {
        this.color = color
        this.model = model
    }
    getDetails () {
        return `Эта ${this.model} велосипеда имеет ${this.color} цвет.`
    }
}

JSR
MDN

Что такое замыкание?


Замыкание — это комбинация функции и ее лексического окружения. Проще говоря, замыкание — это когда внутренняя функция имеет доступ к переменным, объявленным во внешней функции. Замыкание имеет цепочку из трех областей видимости:

  • Собственная область видимости
  • Область видимости внешней функции
  • Глобальная область видимости

function Welcome (name) {
    var greetingInfo = function (message) {
        console.log(message + ' ' + name)
    }
    return greetingInfo
}
var myFunction = Welcome('Иван')
myFunction('Добро пожаловать, ') // Добро пожаловать, Иван
myFunction('Привет, ') // Привет, Иван

JSR
MDN

Что такое модуль?


Модули — это небольшие части независимого переиспользуемого кода, лежащие в основе многих шаблонов проектирования. Большинство модулей экспортируется в качестве объектов, функций или конструкторов.
JSR
MDN

Зачем нужны модули?


Среди прочего, можно назвать следующее:

  • Повышение читаемости и облегчение поддержки кода
  • Возможность повторного использования кода
  • Сохранение чистоты глобального пространства имен

JSR
MDN

Что такое область видимости?


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

Что такое сервис-воркер (service worker)?


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

Как взаимодействовать с объектной моделью документа (Document Object Model, DOM) с помощью сервис-воркеров?


Сервис-воркеры не имеют прямого доступа к DOM. Однако, они могут взаимодействовать со страницей через интерфейс postMessage, а страница — может изменять DOM.
MDN — ServiceWorker
MDN — postMessage

Как повторно использовать информацию при перезапуске сервис-воркера?


Одной из проблем сервис-воркеров является то, что их выполнение прекращается, когда они не используются, и повторно запускается при необходимости. Это не позволяет добавлять обработчики событий fetch и message глобально. Для повторного использования информации необходимо обеспечить взаимодействие сервис-воркеров с индексированной базой данных (IndexedDB) или локальным хранилищем (local storage).
MDN

Что такое индексированная база данных (IndexedDB)?


IndexedDB — это низкоуровневый прикладной интерфейс для хранения большого объема структурированных данных, включая файлы и blobs, на стороне клиента. Данный интерфейс использует индексы для высокопроизводительного поиска данных.
JSR
MDN

Что такое веб-хранилище (Web Storage)?


Веб-хранилище — это интерфейс, позволяющий хранить данные в виде пар ключ/значение локально, т.е. в браузере пользователя, более удобным способом, чем при использовании куки. Веб-хранилище предоставляет два механизма хранения данных:

  • Локальное хранилище (local stotage) — хранит данные текущего пользователя неограниченное количество времени
  • Сессионное хранилище (session storage) — хранит данные на протяжении текущей сессии, т.е. при закрытии вкладки браузера данные будут потеряны

JSR
MDN

Что такое postMessage?


postMessage — это способ коммуникации разных источников объекта window (например, страницы и генерируемого ею поп-апа (всплывающего окна) или страницы и встроенного в нее iframe). Обычно, скрипты одной страницы не имеют доступа к другой странице, если данная страница следует политике общего происхождения или, как еще говорят, одного источника (источники должны иметь одинаковый протокол, хост и порт).

Что такое куки (cookie)?


Куки — это небольшой фрагмент данных, который сохраняется на компьютере пользователя для последующего использования браузером. Куки сохраняются в виде пар ключ/значение:

document.cookie = 'username=John'



JSR
MDN

Зачем нужны куки?


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

  • При первом посещении страницы профиль пользователя сохраняется в куки
  • При повторном посещении страницы профиль пользователя извлекается из куки

JSR
MDN

Какими возможностями обладают куки?


По умолчанию, куки удаляются при закрытии браузера, однако это можно изменить, установив время жизни (expires) (в формате UTC):

document.cookie = 'username=John; expires=Sat, 5 Sep 2020 12:00:00 UTC'

По умолчанию, куки принадлежат текущей странице, однако это также можно изменить, установив путь (path):

document.cookie = 'username=John; path=/services'

JSR
MDN

Как удалить куки?


Удалить куки можно, установив прошедшее время в качестве времени жизни. В этом случае не нужно определять значение куки:

document.cookie = 'username=; expires=Fri, 05 Jun 2020 00:00:00 UTC; path=/;'

Обратите внимание, что в данном случае необходимо определить путь для удаления правильного куки. Некоторые браузеры не позволяют удалить куки без указания этого параметра.
JSR
MDN

В чем разница между куки, локальным и сессионным хранилищами?


Основные отличия состоят в следующем:
Критерий Куки Локальное хранилище Сессионное хранилище
Доступность Как на сервере, так и на клиенте Только на клиенте Только на клиенте
Время жизни Устанавливается с помощью expires До удаления пользователем До закрытия вкладки браузера
Поддержка шифрования Поддерживается Не поддерживается Не поддерживается
Максимальный размер данных 4 Кб Около 5 Мб (зависит от браузера) Около 5 Мб (зависит от браузера)

JSR — Куки
MDN — Cookie
JSR — LocalStorage, SessionStotage
MDN — Web Storage

В чем главное отличие между локальным и сессионным хранилищами?


Локальное хранилище — это тоже самое, что и сессионное хранилище, за исключением того, что в первом данные сохраняются даже при закрытии и перезагрузке браузера, а во втором данные удаляются по окончании сессии страницы.
JSR
MDN

Как получить доступ к веб-хранилищу?


Объект window предоставляет объекты WindowLocalStorage и WindowSessionStorage, которые имеют свойства localStorage и sessionStorage, соответственно. Эти свойства создают экземпляр объекта Storage, с помощью которого можно записывать, извлекать и удалять данные для определенного домена и типа хранилища (сессионное или локальное):

// сохраняем данные
localStorage.setItem('data', document.querySelector('.data').value)
// получаем данные
localStorage.getItem('data')

JSR
MDN

Какие методы предоставляет сессионное хранилище?


Сессионное хранилище предоставляет методы для чтения, записи и удаления данных:

// записываем данные
sessionStorage.setItem('key', 'value')
// получаем данные
const data = sessionStorage.getItem('key')
// удаляем определенные данные
sessionStorage.removeItem('key')
// удаляем все данные
sessionStorage.clear()

JSR
MDN

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


При изменении хранилища в контексте другого документа возникает событие storage:

window.onstorage = function () {}

Пример обработки данного события:

window.onstorage = ev => {
    console.log(`${ev.key} был изменен.\n Старое значение: ${ev.oldValue}.\n Новое значение: ${ev.newValue}.`)
}

Данное событие, в частности, позволяет реализовать своего рода чат.
JSR
MDN

Для чего используется веб-хранилище?


Веб-хранилище является более безопасным и может хранить больший объем данных, чем куки, что не влияет на производительность. Кроме того, данные не отправляются на сервер (в случае с куки данные включаются в заголовки запроса и ответа при каждом обращении клиента к серверу). Поэтому такой способ хранения данных является более предпочтительным, чем куки.
JSR
MDN

Как определить поддержку веб-хранилища браузером?


Перед использованием веб-хранилища рекомендуется проверить поддержку данного интерфейса браузерами:

if (typeof(Storage) !== 'undefined') {
    // код
} else {
    // веб-хранилище не поддерживается
}
// или
if ('Storage' in window) {
    console.log('ok')
} else {
    console.warn('!ok')
}

По данным CanIUse поддержка веб хранилища на сегодняшний день составляет 98%.

JSR
MDN

Как определить поддержку сервис-воркеров браузером?


Перед использованием сервис-воркеров рекомендуется проверить поддержку данного интерфейса браузерами:

if (typeof(Worker) !== undefined) {
    // код
} else {
    // сервис-воркеры не поддерживаются
}
// или
if ('Worker' in window) {
    console.log('ok')
} else {
    console.warn('!ok')
}

По данным CanIUse поддержка сервис-воркеров на сегодняшний день составляет 94,5%.

MDN

Приведите пример веб-воркера


Для использования веб-воркера необходимости сделать следующее.

Создать файл для воркера, например, counter.js:

let i = 0
function timedCount() {
    i = i + 1
    postMessage(i)
    setTimeout('timedCount()', 500)
}
timedOut()

Метод postMessage() используется для отправки сообщения странице.

Создаем объект воркера:

const w = new Worker('counter.js')

После этого обрабатываем получение сообщений от воркера:

w.onmessage = ev => document.querySelector('.message').textContent = ev.data

Воркер будет продолжать обрабатывать событие message даже после того, как внешний скрипт выполнит свою работу, поэтому нужно принудительно его остановить:

w.terminate()

Если присвоить воркеру значение undefined, код можно будет использовать повторно:

w = undefined

MDN

Назовите ограничения веб-воркеров по работе с DOM


Поскольку веб-воркеры создаются в отдельном файле, они не имеют доступа к следующим объектам:

  • window
  • Document
  • Родительский объект, т.е. объект, запустивший воркер

MDN

Что такое промис (обещание, promise)?


Промис — это объект, который либо выполняется с некоторым значением, либо отклоняется с ошибкой. Разрешение промиса происходит либо после истечения определенного времени, либо после возникновения определенного события. Промис может иметь одно из трех состояний: находится в режиме ожидания (pending), выполнен (fulfilled), отклонен (rejected).

Синтаксис промиса:

const promise = new Promise((resolve, reject) => {
    // код
})
// или, когда мы уверены, что промис выполнится успешно
const promise = Promise.resolve(value)
promise.then(value => {
    // код
})

Пример использования промиса:

const promise = new Promise(resolve => {
    const timer = setTimeout(() => {
        resolve('Привет от промиса!')
        clearTimeout(timer)
    }, 5000);
}, reject => {
    reject('Что-то пошло не так!')
})
promise
    .then(value => console.log(value))
    .catch(error => console.error(error))
    .finally(() => console.log('Мы закончили')) // в консоль будет выведено "Привет от промиса!" через 5 секунд и "Мы закончили"

Алгоритм выполнения промиса:



JSR
MDN

Зачем нужны промисы?


Промисы используются для работы с асинхронным кодом. Они представляют собой альтернативу функциям обратного вызова, позволяя избежать так называемого «ада колбеков», делают код более чистым и читаемым.
JSR
MDN

Назовите три возможных состояния промиса


У промисов существует три состояния:

  • Ожидание: стадия перед началом выполнения операции
  • Выполнен: успешное завершение операции
  • Отклонен: неудачное выполнение операции. Выбрасывается исключение.

JSR
MDN

Что такое функция обратного вызова (колбек)?


Колбек — это функция, которая передается другой функции в качестве аргумента. Данная функция (внутренняя) вызывается внутри родительской (внешней) для выполнения определенной операции. Рассмотрим простой пример:

function callback(name) {
    alert(`Привет, ${name}!`)
}
function outer(cb) {
    const name = prompt('Пожалуйста, введите свое имя')
    cb(name)
}
outer(callback)

В приведенном примере функция outer запрашивает имя пользователя и записывает его в переменную name. Затем данная функция передает name функции callback, которая выводит приветствие с именем пользователя.

JSR
MDN

Зачем нужны колбеки?


Колбеки нужны, поскольку JavaScript — язык, управляемый событиями. Это означает, что вместо ожидания ответа на запрос или обработки определенного события, JS продолжает реагировать на другие события. Рассмотрим пример, в котором одна функция обращается к интерфейсу, а другая — выводит сообщение в консоль:

function first () {
    // имитируем обращение к API
    setTimeout(() => console.log('Вызвана первая функция.'), 1000)
}
function second () {
    console.log('Вызвана вторая функция.')
}
first()
second()
// сначала будет выведено "Вызвана вторая функция.", затем "Вызвана первая функция."

Как видите, JS не ожидает завершения первой функции, а продолжает выполнение кода. Поэтому колбеки используются для имитации асинхронности, предотвращая блокировку основного потока выполнения программы.

JSR
MDN

Что такое ад колбеков?


Ад колбеков — это антипаттерн, когда множество функций обратного вызова вложены друг в друга для реализации асинхронной логики. Такая структура кода сложна для восприятия и поддержки. Это выглядит примерно так:

function first () {
    return function second () {
        return function third () {
            return function fourth () {
                // и т.д.
            }
        }
    }
}

Такой подход к написанию кода считается плохой практикой, кроме случаев каррирования (включая debounce и throttle) или частичного применения функций.
JSR
MDN

Что такое события, отправленные сервером (server-sent events, SSE)?


События, отправленные сервером — это технология пуш-уведомлений, позволяющая браузерам получать от сервера обновленные данные через HTTP-соединение без отправки запроса. Это один из способов коммуникации клиента и сервера, когда сообщения отправляются только сервером. Данная технология используется для обновления Facebook/Twitter, цен в магазинах, новостных лент и т.д.
JSR
MDN

Как получать сообщения (уведомления или события), отправленные сервером?


Для этого используется объект «EventSource»:

if('EventSource' in window) {
    const source = new EventSource('sse_generator.js')
    source.onmessage = event => document.querySelector('output').innerHTML += event.data + ''
}

JSR
MDN

Как проверить поддержку SSE браузером?


Это делается так:

if (typeof EventSource !== 'undefined') {
    // код
} else {
    // SSE не поддерживается
}
// или
('EventSource' in window)
    ? console.log('ok')
    : console.warn('!ok')

По данным CanIUse на сегодняшний день SSE поддерживается 95% браузеров.
JSR
MDN

Какие события возникают при работе с SSE?


Вот список этих событий:
Событие Описание
open Возникает при открытии соединения с сервером
message Возникает при получении сообщения от сервера
error Возникает при выбрасывании исключения

JSR
MDN

Назовите основные правила работы с промисами


Основными правилами работы с промисами является следующее:

  • Промис — это объект, содержащий встроенный или стандартный метод then()
  • Стадия ожидания промиса, обычно, заканчивается стадией его выполнения или отклонения
  • Состояние выполненного или отклоненного промиса не должно меняться после его разрешения
  • После разрешения промиса его значение также не должно меняться

JSR
MDN

Что такое колбек в колбеке?


Вы можете вкладывать колбеки друг в друга с целью последовательного выполнения определенных операций:

loadScript('/script1.js', script => {
    console.log(`Скрипт ${script} загружен.`)
    loadScript('/script2.js', script => {
        console.log(`Скрипт ${script} загружен.`)
        loadScript('/script3.js', script => {
            console.log(`Скрипт ${script} загружен.`)
        })
    })
})

JSR
MDN

Что такое цепочка из промисов?


Последовательное выполнение нескольких асинхронных задач с помощью промисов называется цепочкой промисов. Рассмотрим пример:

new Promise((resolve, reject) => {
    const id = setTimeout(() => {
        resolve(1)
        clearTimeout(id)
    }, 1000)
}).then(result => {
    console.log(result) // 1
    return result * 2
}).then(result2 => {
    console.log(result2) // 2
    return result2 * 3
}).then(result3 => {
    console.log(result3) // 6
}).catch(error => console.error(error))

Алгоритм выполнения:

  • Первый промис разрешается со значением 1
  • После этого, первый метод then() выводит это значение в консоль и возвращает его, умножая на 2
  • Второй then() выводит результат первого then() в консоль (2) и возвращает результат, умножая его на 3
  • Последний then() выводит результат второго then() в консоль (6)
  • Блок catch служит для обработки ошибок

JSR
MDN

Что такое Promise.all()?


Promise.all() — это промис, принимающий массив других промисов в качестве аргумента и возвращающий результаты выполненных промисов или ошибку при отклонении одного из них. Синтаксис:

Promise.all([Promise1, Promise2, Promise3])
    .then(results => console.log(results))
    .catch(error => console.error(error))

Помните, что порядок получения результатов зависит от порядка промисов в массиве.
MDN
JSR

Что такое Promise.race()?


Метод Promise.race() возвращает результат первого выполненного или отклоненного промиса из переданных ему в виде массива промисов:

const promise1 = new Promise((resolve, reject) => setTimeout(resolve, 500, 'один'))
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'два'))
Promise.race([promise1, promise2]).then(value => console.log(value)) // "два"

MDN
JSR

Что такое строгий режим?


Для включения строго режима используется инструкция 'use strict' (или «use strict») в начале всего кода или отдельной функции. Строгий режим был представлен в ES5. В данном режиме запрещены некоторые действия и выбрасывается больше исключений.
MDN
JSR

Зачем нужен строгий режим?


Строгий режим позволяет писать более безопасный код, предотвращая возникновение многих ошибок. Например, он запрещает случайное создание глобальных переменных (без ключевого слова, variable = value), присваивание значения свойству, доступному только для чтения, свойству, которое можно получить только с помощью геттера, несуществующему свойству и несуществующей переменной или объекту. В нестрогом режиме во всех этих случаях исключение не выбрасывается.
MDN
JSR

Как включить строгий режим?


Строгий режим включается с помощью инструкции 'use strict' (или «use strict») в начале кода или функции. Обычно, данная инструкция указывается в самом начале скрипта, т.е. в глобальном пространстве имен:

'use strict'
x = 3.14 // Uncaught ReferenceError: x не определена

Если 'use strict' указывается в функции, то действие строгого режима распространяется только на эту функцию:

x = 3.14 // все в порядке
f() // Uncaught ReferenceError: y не определена
function f () {
    'use strict'
    y = 3.14
}

MDN
JSR

Для чего используется двойное отрицание?


Двойное отрицание (!!) преобразует значение в логическое. Если значение является ложным, то возвращается false, иначе — true:

const x = 1
console.log(x) // 1
console.log(!!x) // true
const y = ''
console.log(y) // ''
console.log(!!str) // false

Помните: "!!" — это не отдельный оператор, а два оператора "!".
MDN
JSR

Для чего используется оператор «delete»?


Данный оператор служит для удаления свойств объектов и значений этих свойств:

const user = {
    name: 'Иван',
    age: 20
}
delete user.age
console.log(user) // { name: "Иван" }
delete user // false
// в строгом режиме будет выброшено исключение Uncaught SyntaxError: использование оператора Delete в строгом режиме недопустимо

Помните, что поскольку массив — это тоже объект, применение delete к элементу массива, удалит его значение и запишет в него undefined, т.е. индекс элемента массива сохранится и длина массива не изменится
JSR
MDN

Для чего используется оператор «typeof»?


Данный оператор используется для определения типа переменной или выражения:

typeof 1 // number
typeof [] // object
typeof 'Иван Иванов' // string
typeof (1 + 2) // number
typeof null // object (?)
typeof NaN // number (?)

JSR
MDN

Что такое undefined?


undefined — это неопределенное (не отсутствующее) стандартное значение (значение по умолчанию) переменной, которой не было присвоено значения, а также необъявленной переменной. Это один из примитивных типов данных:

let name
console.log(typeof name) // undefined
console.log(typeof age) // undefined

Данное значение может присваиваться переменным явно:

user = undefined

JSR
MDN

Что такое null?


null — значение, представляющее собой отсутствие значения, установленное явно. Это один из примитивных типов данных. С помощью null можно удалить значение переменной:

const user = null
console.log(typeof user) // object

JSR
MDN

В чем разница между null и undefined?


Основные отличия состоят в следующем:
Null Undefined
Присваивается в качестве индикатора отсутствия значения Является значением по умолчанию для переменных, которым не было присвоено значения, или необъявленных переменных
Тип — object Тип — undefined
Примитивный тип, означающий нуль, отсутствие значения или ссылки Примитивный тип, означающий, что переменной не было присвоено значения
Указывает на отсутствие значения переменной Указывает на отсутствие переменной или неопределенность ее значения

JSR — undefined
MDN — undefined
JSR — null
MDN — null

Что такое eval?


Функция eval() вычисляет переданную ей строку. Строка может быть выражением, переменной, одним или несколькими операторами:

console.log(eval('1 + 2')) // 3
// пример с каррированием
const calc = a => b => c =>
    (c === '+' || c === '-' || c === '*' || c === '/')
        ? eval(`a ${c} b`)
        : 'Некорректная операция!'
calc(10)(5)('+') // 15

Использовать не рекомендуется по причинам безопасности.
JSR
MDN

В чем разница между window и document?


Основные отличия состоят в следующем:
Window Document
Является корневым узлом (верхним элементом) любой страницы Является прямым потомков объекта window. Также известен как Document Object Model (DOM)
Доступен по умолчанию (поэтому вместо window.property можно использовать property, например, вместо window.localStorage, можно использовать localStorage) Доступен через window.document или просто document
Имеет методы alert(), prompt() и т.д., а также свойства document, location и др. Имеет методы getElementById(), getElementsByClassName(), querySelector() и т.д.

JSR — Глобальный объект
MDN — window
JSR — DOM
MDN — DOM

Как получить доступ к истории браузера?


Информацию об истории перемещений между страницами в браузере содержит свойство history объекта window. Для перехода к предыдущей или следующей странице следует использовать методы back(), next() или go():

const goBack = () => {
    history.back()
    // или
    history.go(-1)
}
const goForward = () => history.forward()

MDN

Какие типы данных существуют в JavaScript?


В JavaScript есть 8 основных типов:

  • number для любых чисел: целочисленных или чисел с плавающей точкой, целочисленные значения ограничены диапазоном ±253
  • bigint для целых чисел произвольной длины
  • string для строк. Строка может содержать один или больше символов, нет отдельного символьного типа
  • boolean для true/false
  • null для неизвестных значений – отдельный тип, имеющий одно значение null
  • undefined для неприсвоенных значений – отдельный тип, имеющий одно значение undefined
  • object для более сложных структур данных
  • symbol для уникальных идентификаторов

JSR
MDN

Что делает isNaN()?


Функция isNaN() преобразует значение в число и проверяет, является ли оно NaN.

isNaN('hello') // true
isNaN(100) // false

Более надежной версией данной функции является метод Number.isNaN(), представленный в ES6.
JSR
MDN

В чем разница между необъявленными и неопределенными переменными?


Основные отличия заключаются в следующем:
Необъявленные Неопределенные
Не существуют в программе Были объявлены без присвоения значения
Попытка доступа заканчивается ошибкой При попытке получить доступ возвращается undefined
Поднимается (всплывает) в начало текущей области видимости Также поднимается, но без присвоенного значения, т.е. со значением undefined (поднимается только объявление, но не инициализация)

JSR
MDN

Что такое глобальные переменные?


В браузере глобальные функции и переменные, объявленные с помощью ключевого слова «var», или без использованию ключевого слова (в нестрогом режиме), становятся свойствами глобального объекта window (не работает в модулях). Такие переменные доступны из любого места программы. Использовать глобальные переменные не рекомендуется. При необходимости создания глобальной переменной лучше сделать это явно:

window.currentUser = {
    name: 'Иван'
}
// или
globalThis.currentUser = {
    name: 'Иван'
}
console.log(currentUser.name) // Иван

JSR

Какие проблемы влечет за собой создание глобальных переменных?


Создание глобальных переменных приводит к загрязнению глобального пространства имен, что может вызвать конфликт между названиями переменных. Это также усложняет отладку и тестирование кода.
JSR

Что такое NaN?


Глобальное свойство NaN является значением, представляющим собой не число (Not-a-Number). Точнее, NaN указывает на то, что значение является неправильным, но все-таки числом. Поэтому typeof NaN возвращает number.

parseInt('bla') // NaN
Math.sqrt(-1) // NaN

MDN

Что делает isFinite()?


Глобальная функция isFinite() преобразует аргумент в число и возвращает true, если оно является обычным (конечным) числом, т.е. не NaN, Infinity (положительная бесконечность), -Infinity (отрицательная бесконечность). В противном случае, возвращается false.

isFinite(Infinity) // false
isFinite(-Infinity) // false
isFinite(NaN) // false
isFinite(100) // true

Также существует метод Number.isFinite(), который в отличие от isFinite() не преобразует аргумент в число перед проверкой.
MDN
JSR

Что такое поток событий (event flow)?


Поток событий (распространение событий) — это порядок, в котором событие возникает на странице. Когда вы кликаете по элементу, вложенному в другие элементы, перед тем как событие достигнет целевого элемента, оно последовательно пройдет через все его родительские элементы, начиная от глобального объекта window. Существует три стадии распространения события:

  • Сверху вниз — стадия захвата или погружения
  • Целевая стадия
  • Снизу вверх — стадия всплытия

JSR

Что такое всплытие события?


Всплытие — это стадия распространения события, когда событие сначала регистрируется на целевом элементе, а затем по цепочке из предков данного элемента поднимается до самого верхнего (внешнего) элемента — глобального объекта window.
JSR

Что такое погружение или захват события?


Погружение — это стадия возникновения события, когда оно сначала регистрируется на самом верхнем (внешнем) элементе (глобальном объекте window), а затем спускается вниз по цепочке из предков до целевого элемента.
JSR

Как отправить форму на обработку?


Это можно сделать разными способами:

function submitForm() {
    document.forms[0].submit()
}
form.onsubmit = function(event) {
    event.preventDefault()
    // код
}
form.addEventListener('submit', event => {
    event.preventDefault()
    // код
})

Любая кнопка в форме по умолчанию имеет тип submit, т.е. служит для отправки формы.
MDN
JSR

Как получить информацию об операционной системе?


Данную информацию содержит глобальный объект navigator. Некоторую часть этой информации можно получить через его свойство platform:

console.log(navigator.platform)

MDN

В чем разница между событиями «DOMContentLoaded» и «load»?


Событие «DOMContentLoaded» возникает, когда первоначальный HTML документ полностью загружен и разобран без ожидания полной загрузки таблиц стилей, изображений или фреймов. Событие «load» возникает после полной загрузки страницы, включая все дополнительные ресурсы.
MDN — DOMContentLoaded
MDN — load
JSR

В чем разница между нативными, хостовыми (принадлежащими среде выполнения кода) и пользовательскими объектами?


Нативные объекты (native objects) являются частью языка и определяются в спецификации ECMAScript. Такими объектами являются, например, Number, String, Function, Object, Math, RegExp, Date и т.д. Хостовые объекты (host objects) предоставляются браузером или другой средой выполнения, например, Node.js. Такими объектами являются, например, window, document (DOM), XMLHttpRequest, Web API (стек вызовов — call stack, очередь задач — task queue) и др. Пользовательскими объектами (user objects) являются любые объекты, создаваемые в коде, например, объект, содержащий информацию о пользователе:

const user = {
    name: 'Иван',
    age: 20
}

JSR
MDN

Какие средства используются для отладки кода?


Такими средствами являются:

  • Инструменты разработчика в браузере, например, Chrome DevTools
  • Выражение «debugger»
  • Старый-добрый console.log()

JSR
MDN — debugger
MDN — Console

В чем заключаются преимущества и недостатки промисов по сравнению с колбеками?


Преимущества:

  • Предотвращают ад колбеков
  • Позволяют выполнять асинхронный код последовательно с помощью then()
  • Позволяют выполнять асинхронный код параллельно с помощью Promise.all()
  • Решают многие проблемы колбеков (слишком поздний или слишком ранний вызов, несколько вызовов вместо одного, скрытие ошибок)

Недостатки

  • Код становится сложнее писать
  • Для обеспечения поддержки старыми браузерами нужен полифил (таких браузеров на сегодняшний день почти не осталось)

JSR — Промисы
MDN — Promise
JSR — Колбеки
MDN — Callback

В чем разница между атрибутом и свойством элемента?


Когда браузер загружает страницу, он разбирает HTML и генерирует из него DOM-объекты. Для узлов-элементов большинство стандартных HTML-атрибутов автоматически становятся свойствами DOM-объектов. Т.е. атрибут элемента указывается в разметке, а его свойство в DOM. Например, для тега «body» с атрибутом id=«page» у DOM-объекта будет свойство body.id=«page».

<input type="text" value="Доброе утро!">
// данный элемент имеет два атрибута: type и value
const input = document.querySelector('input')
// получаем атрибут
console.log(input.getAttribute('value'))
// получаем свойство
console.log(input.value)
// меняем значение атрибута
input.setAttribute('value', 'Добрый вечер!')
// меняем значение свойства
input.value = 'Добрый вечер!'

JSR

Что такое политика общего происхождения (same-origin policy)?


Политика общего происхождения (одинакового источника) блокирует доступ к данным из другого источника. Источником является сочетание домена, хоста и порта. По умолчанию, совместное использование ресурсов (cross-origin resource sharing, CORS) запрещено, т.е. данные предоставляются только в ответ на запрос из того же источника, в котором они находятся. Это поведение можно изменить с помощью специальных HTTP-заголовков.
JSR
MDN — SOP
MDN — CORS

Что делает void 0?


Оператор void вычисляет переданное выражение и возвращает undefined. Обычно, когда мы кликаем по ссылке, браузер загружает новую сраницу или перезагружает текущую. С помощью выражения «void(0)» можно этого избежать:

<a href="javascript:void(0)" onclick="alert('Привет!')">Нажми на меня!
</a>

Перезагрузку страницы также можно предотвратить с помощью заглушки:

<a href="#">Битая ссылка</a>
// в этом случае символ "#" добавляется к URL в адресной строке

MDN

JavaScript — это компилируемый или интерпретируемый язык программирования?


Сам по себе JavaScript — это интерпретируемый язык программирования. Движок (runtime, engine) разбирает код, интерпретирует каждую строку и выполняет ее. Однако, в современных браузерах используется технология под названием «компиляция на лету» (just-in-time, JIT compilation), когда код компилируется перед выполнением. Это увеличивает время подготовки к выполнению кода, но существенно ускоряет само выполнение.
JSR
MDN

Чувствителен ли JavaScript к регистру?


Да, JavaScript чувствителен к регистру. Поэтому ключевые слова, названия переменных, функций и объектов должны быть идентичными при их использовании. Например, const somename и const someName — это разные переменные, typeof(1) — number, а typeOf 1 — ReferenceError: typeOf не определена.
JSR
MDN

Связаны ли Java и JavaScript?


Нет, это два совершенно разных языка программирования. Однако, они оба относятся к объектно-ориентированным языкам и, как и множество других языков, используют похожий синтаксис (if, else, for, switch, break, continue и т.д.). Java в JavaScript — это маркетинговый ход.
JSR
MDN

Что такое событие (event)?


Событие — это реакция браузера на определенное действие. Таким действием может быть действие пользователя, например, нажатие кнопки или ввод текста, загрузка страницы, получение ответа на запрос и т.д. (т.е. действия, приводящие к возникновению событий, не обязательно зависят от пользователя). События регистрируются с целью их дальнейшей обработки.

button.onclick = () => alert('Привет!')
input.addEventListener('change', function() {
    p.textContent = this.value
})
window.onload = () => console.log('Страница полностью загружена.')

MDN
JSR

Дополнительная литература


Habr — Из чего сделан JavaScript?
Habr — Как работает JS: о внутреннем устройстве V8 и оптимизации кода
Medium — Разбираемся с путаницей между JavaScript методами slice(), splice() и split()
Medium — Prototypes in JavaScript
Medium — Understanding Prototypes in JavaScript
Medium — Подробно о методах apply(), call() и bind(), необходимых каждому JavaScript разработчику
DigitalOcean — Знакомство с объектами map и set в JavaScript
Medium — Why Should We Stop Using Objects As Maps in JavaScript?
Habr — 5 рекомендаций по написанию качественных стрелочных функций
Habr — Каррирование функций в JavaScript
Medium — Понимаем каррирование в JavaScript
Medium — Curry and Function Composition
Habr — Зачем в JavaScript нужен строгий режим?
Medium — Advanced JavaScript ES6 — Temporal Dead Zone, Default Parameters And Let vs Var — Deep dive!
Medium — Понимаем немедленно вызываемые функции IIFE и немного больше
Habr — Почему пора перестать использовать JavaScript IIFE
Habr — Мемоизация в JS и ускорение функций
Medium — What is Memoization in Javascript?
Medium — Разбираемся с “поднятием” (hoisting) в JavaScript
DigitalOcean — Понимание понятия классов в JavaScript
Habr — Как работает JS: классы и наследование, транспиляция в Babel и TypeScript
Habr — Классы и фабричные функции в JavaScript. Что выбрать?
Medium — JavaScript Classes: An In-Depth look (Part 1)
Medium — Понимаем замыкания в JavaScript. Раз и навсегда
Habr — Замыкания в JavaScript для начинающих
Habr — Дэн Абрамов о замыканиях в JavaScript
Habr — Понимание (всех) «модульных» форматов и инструментов JavaScript
FreeCodeCamp — JavaScript Modules: A Beginner’s Guide
Habr — Использование JavaScript-модулей в продакшне: современное состояние дел. Часть 1
Medium — Introduction to ES6 modules
Habr — Области видимости в JavaScript
DP — JavaScript Scope Explained in Simple Words
Habr — Визуализация работы сервис-воркеров
Habr — Как работает JS: сервис-воркеры
Habr — Service Workers. Инструкция по применению
GoogleDevelopers — Service Workers: an Introduction
Habr — 5 малоизвестных возможностей JSON.stringify()
Habr — Хранилище для веба
Habr — Как работает JS: системы хранения данных
WebDevBlog — Изучаем IndexedDB
GoogleDevelopers — Working with IndexedDB
Medium — A quick but complete guide to IndexedDB and storing data in browsers
Habr — Web Storage API: примеры использования
Medium — Как работать с localStorage в JavaScript
Habr — Как работает JS: веб-воркеры и пять сценариев их использования
Habr — Прослушиватели событий и веб-воркеры
Medium — A Simple Introduction to Web Workers in JavaScript
Habr — Использование промисов в JavaScript
Habr — Элегантное асинхронное программирование с помощью промисов
Habr — Визуализация промисов и Async/Await
Habr — Распространенные ошибки при работе с промисами в JavaScript, о которых должен знать каждый
Medium — Understanding Throttling and Debouncing
Redd — Debounce vs Throttle: Definitive Visual Guide
Medium — A Look at Server-Sent Events
Habr — SSEGWSW: Server-Sent Events Gateway by Service Workers
GoogleDeveloper — Get Started with Debugging JavaScript in Chrome DevTools
Microsoft — Отладка приложения JavaScript или TypeScript в Visual Studio
Habr — Политика общего происхождения и CORS: визуальное руководство