JS Flashcards

You may prefer our related Brainscape-certified flashcards:
1
Q

Что такое приведение или преобразование типов (type coercion)

A

Приведение (или преобразование) типов — это процесс преобразования значения из одного типа в другой.
В JavaScript преобразование типов может быть явным и неявным. Преобразование с помощью функции-конструктора является явным. Пример:
const num = Number("123");
const boolValue = Boolean(0);

Так как JavaScript — это язык со слабой типизацией, значения в нем могут быть конвертированы между различными типами автоматически - это называется неявным преобразованием типов. Пример:
if (value) {…};
const result = "3" * 2;
const comparison = 5 == "5";

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Что такое apply?

A

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

function.apply(thisArg, [argsArray])

Пример использования apply():
function greeting(greet, punctuation) {
return ${greet}, ${this.name}${punctuation};
}
const person = {
name: ‘Alice’

console.log(greeting.apply(person, [‘Hello’, ‘!’]));
// Вывод: Hello, Alice!

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Как отфильтровать массив?

A

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

Формат метода filter():
array.filter(callback(element[, index[, array]])[, thisArg])

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evenNumbers = numbers.filter((num) => {
return num % 2 === 0;
});
console.log(evenNumbers); // Выводит: [2, 4, 6, 8, 10]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Базовые операторы в JS

A

Операнд – то, к чему применяется оператор. Например, в умножении 5 * 2 есть два операнда: левый операнд равен 5, а правый операнд равен 2. Иногда их называют «аргументами» вместо «операндов».

Унарным называется оператор, который применяется к одному операнду. Например, оператор унарный минус “-“ меняет знак числа на противоположный

Бинарным называется оператор, который применяется к двум операндам. Тот же минус существует и в бинарной форме.

Поддерживаются следующие математические операторы:
Сложение +,
Вычитание -,
Умножение *,
Деление /,
Взятие остатка от деления %,
Возведение в степень **.
Если бинарный оператор ‘+’ применить к строкам, то он их объединяет в одну - это называется конкатенация.
Унарным плюсом можно быстро привести операнд к числу.

Одной из наиболее частых числовых операций является увеличение или уменьшение на единицу.
Инкремент ++ увеличивает переменную на 1
Декремент – уменьшает переменную на 1
Операторы ++ и – могут быть расположены не только после, но и до переменной. Префиксная форма возвращает новое значение, в то время как постфиксная форма возвращает старое (до увеличения/уменьшения числа).
Когда оператор идёт после переменной — это «постфиксная форма»: counter++.
«Префиксная форма» — это когда оператор идёт перед переменной: ++counter.
Оператор «запятая» предоставляет нам возможность вычислять несколько выражений, разделяя их запятой ,. Каждое выражение выполняется, но возвращается результат только последнего.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

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

A

Есть восемь основных типов данных в JavaScript.

  1. Числовой тип данных (number) представляет как целочисленные значения, так и числа с плавающей точкой.
    Кроме обычных чисел, существуют так называемые «специальные числовые значения», которые относятся к этому типу данных: Infinity, -Infinity (можем получить в результате деления на ноль) и NaN (NaN означает вычислительную ошибку. Это результат неправильной или неопределённой математической операции).
  2. BigInt числовой примитив, который позволяет использовать большие числа с высокой точностью. Чтобы создать значение типа BigInt, необходимо добавить n в конец числового литерала: const bigInt = 1234567890123456789012345678901234567890n;
  3. Строка (string) в JavaScript должна быть заключена в кавычки. Обратные кавычки имеют расширенную функциональность - позволяют нам встраивать выражения в строку, заключая их в ${…}.
  4. Булевый тип (boolean) может принимать только два значения: true (истина) и false (ложь).
    Такой тип, как правило, используется для хранения значений да/нет: true значит «да, правильно», а false значит «нет, не правильно».
  5. null формирует отдельный тип, который содержит только значение null. Это специальное значение, которое представляет собой «ничего», «пусто» или «значение неизвестно».
  6. Специальное значение undefined означает, что «значение не было присвоено». Если переменная объявлена, но ей не присвоено никакого значения, то её значением будет undefined.
  7. Symbol примитивный тип данных, использующийся для создания уникальных идентификаторов. Даже если символы имеют одно и то же имя, это – разные символы.
  8. Тип object (объект) не является примитивным типом данных. Объекты используются для хранения коллекций различных значений и более сложных сущностей. Объект может быть создан с помощью фигурных скобок {…} с необязательным списком свойств. Свойство – это пара «ключ: значение», где ключ – это строка (также называемая «именем свойства»), а значение может быть чем угодно.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Расскажи про тип данных число.

A

Тип данных “число” (number) в JavaScript представляет числовые значения. Также для этого типа данных существуют специальные значения Infinity, -Infinity и NaN (Not a Number).

В диапазоне от -2 в 53 степени до 2 в 53 степени, числа могут быть представлены точно.

Для типа данных “число” определены стандартные арифметические операции, такие как сложение (+), вычитание (-), умножение (*), деление (/), взятие остатка от целочисленного деления (%), возведение в степень (**), а также операции сравнения (>, <, >=, <=, ==, ===, !=, !==).

Числа также могут быть представлены в различных системах исчисления, таких как двоичная, восьмеричная или шестнадцатеричная системы. Чтобы перевести число в какую-то систему исчисления можно использовать метод toString:
let decimalNumber = 10;
let binaryNumber = decimalNumber.toString(2);
console.log(binaryNumber); // Выводит: 1010

Стандарт IEEE-754 определяет три специальных значения. Эти значения принадлежат типу number, но не работают, как обычные числа:
- бесконечность Infinity;
- минус бесконечность -Infinity;
- не число (not a number) NaN.

Значение NaN используется, чтобы сообщить об операции, результатом которой оказалось не число. В JavaScript существует пять операций, которые могут вернуть NaN:
1. ошибка парсинга числа (например, при попытке превратить строку в число parseInt('привет')).
2. результат математической операции не находится в полей действительных чисел (например, взятие корня от -1).
3. один из операндов в арифметической операции — NaN (5 + NaN)
4. результат арифметической операции не определён для переданных операндов undefined + undefined.
5. арифметическая операция со строкой, кроме сложения 'привет' * 5

Согласно спецификации, NaN не равен самому себе. Для проверки на NaN пользуйтесь функцией Number.isNaN(), которая возвращает true если переданное значение — NaN
Number.isFinite() проверяет и на Infinity, и на Nan - на них возвращается false.

Для округления, взятия корней и других математических операций в JavaScript существует отдельный модуль Math.
round() — округление по обычным правилам;
floor() — округление вниз;
ceil() — округление вверх;
trunc() — отбрасывание дробной части, не обращая внимания на знак аргумента.

Сам по себе примитивный тип «число» не имеет методов. Когда происходит вызов метода у числа, оно автоматически оборачивается в специальную обёртку Number, которая и содержит методы:
- проверки на специальные значения isNaN(), isFinite().
- toString(2) переводит в строку с определенной системой исчисления
- toFixed() форматирует число, обрезая значения после запятой. Возвращает строку, а не число.
Если после округления нужно производить другие арифметические операции, то лучше распарсить число с помощью parseFloat().

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Тип данных BigInt

A

Тип большого целого BigInt — примитивный тип, который представляет целые числа больше 2 в степени 53 - 1. Эти числа уже не помещаются в стандартный примитив «число».

Создать BigInt можно двумя способами.
1️⃣ Добавить суффикс n в конец записи числа:
const biggy = 9997000254740991n
2️⃣ Вызвать конструктор BigInt:
const alsoBig = BigInt(9997000254999999)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Тип данных строка

A

Строки представляют собой последовательность символов. Созданная строка является иммутабельной (immutable) и не может быть изменена.

Есть несколько способов создать строку:
- одинарными кавычками ‘;
- двойными кавычками “;
- шаблонной строкой через обратный апостроф ` - бэктик.

Если в записи одинарными кавычками нужно поставить апостроф, то символ экранируют обратным слэшем . Так мы даём JavaScript понять, что это просто символ, а не закрывающая кавычка.

Строки можно сравнивать между собой, для сравнения используется лексикографический порядок. Это означает, что первые символы алфавита считаются меньше последних.
Алгоритм посимвольно сравнивает строки до первого несовпадения, либо пока не закончится одна из строк.
console.log(‘А’ < ‘Я’) // true
console.log(‘Кот’ > ‘Код’) // true
console.log(‘Код’ < ‘Кодер’) // true
console.log(‘Код’ === ‘Код’) // true
Сравнение учитывает регистр букв, если необходимо регистронезависимое сравнение, то обе строки приводятся к верхнему или нижнему регистру с помощью методов toUpperCase или toLowerCase.

Сам по себе примитивный тип «строка» не имеет методов. Когда происходит вызов метода, оно автоматически оборачивается в специальную обёртку, которая и содержит методы.
length: Возвращает длину строки.
toUpperCase(): Возвращает новую строку, содержащую все символы исходной строки в верхнем регистре.
toLowerCase(): Возвращает новую строку, содержащую все символы исходной строки в нижнем регистре.
substring(startIndex, endIndex): Возвращает подстроку, которая начинается со значения индекса startIndex до значения индекса endIndex (не включительно).
const str = "Hello, world!"; console.log(str.substring(0, 5)); // Вывод: "Hello"
indexOf(substring): Возвращает индекс первого вхождения подстроки substring в строке. Если подстрока не найдена, возвращает -1.
replace(oldSubstring, newSubstring): Заменяет первое вхождение подстроки oldSubstring на подстроку newSubstring и возвращает новую строку.
const str = “Hello, world!”;
console.log(str.replace(“world”, “JavaScript”)); // Вывод: “Hello, JavaScript!” **split(separator)**: Разбивает строку на массив подстрок с использованием указанного разделителя separator`.
trim(): Удаляет пробельные символы с начала и конца строки и возвращает новую строку.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Тип данных Boolean

A

Логический или булев тип boolean может принимать лишь истинное (true) и ложное (false) значения. Значения этого типа используются в условных выражениях.

Создать булевое значение можно несколькими способами.
- явно указать значение, используя ключевые слова true и false:
const truthyValue = true // «Истина»
- использовать метод Boolean:
const falsyValue = Boolean(‘’) // «Ложь»
- использовать выражения, значениями которых будут «истина» или «ложь».
const anotherTruthy = 4 < 5
- Если вызвать одинарное ! или двойное отрицание !!, можно быстро привести любое выражение к логическому типу.

Обычно логическим переменным дают названия, начинающиеся с английских глаголов is, should, does, can и подобных.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Тип данных Undefined

A

**Undefined — это примитивный тип данных, состоящий из одного значения undefined. Оно используется, чтобы обозначить неопределённое значение. **
- JavaScript автоматически устанавливает значение undefined объявленным переменным, которые не были проинициализированы значением.
- JavaScript автоматически устанавливает значение undefined в аргумент функции, если значение не передали при вызове
hello('Витя') // Привет, Витя hello() // Привет, undefined

Вручную установленное undefined используют, чтобы обозначить неизвестное значение:
const person = { name: 'Пётр', lastName: 'Романов', age: undefined }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Тип данных Null

A

Null — это примитивный тип данных, который состоит из единственного значения null. Значение null используют, когда нужно обозначить намеренное отсутствие значения.

null обозначает понятия «отсутствует», «ничего», «пусто» или «значение неизвестно». Оно всегда явно задаётся программистом, JavaScript автоматически не устанавливает его.
В JavaScript null используется только для обозначения конца цепочки прототипов, чтобы показать, что следующий прототип отсутствует.
В языке существует похожий примитив undefined, он обозначает, что значение ещё не установлено. Их можно легко спутать, потому что оба обозначают отсутствие значения. Разница состоит в том, что null обозначает намеренное отсутствие, а undefined — неявное.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Тип данных Symbol

A

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

Для создания символа нужно вызвать функцию Symbol:
const sym = Symbol() const symTwo = Symbol() console.log(sym === symTwo) // false

Символы используются для создания скрытых свойств объектов. В отличие от свойств, ключом которых является строка, символьные свойства может читать только владелец символа. Скрытые свойства не видны при его обходе с помощью for…in. Это может пригодиться, когда необходимо добавить свойства объекту, который могут модифицировать другие части программы. Таким образом только вы сможете читать созданное свойство, а гарантия уникальности символов гарантирует и отсутствие конфликтов имён.

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

Работа с реестром символов организована с помощью двух методов:
- Symbol.for(ключ) — возвращает символ, хранящийся по ключу. Если символа ещё не существует, он создаётся автоматически.
- Symbol.keyFor(символ) — возвращает строковый ключ, который хранит переданный символ или undefined, если символ не
хранится в реестре.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Что такое массив?

A

**Массив - упорядоченная коллекция данных, в которой присутствуют 1-й, 2-й, 3-й элементы и т.д. Например, она понадобится нам для хранения списка чего-либо:
пользователей, товаров, элементов HTML и т.д. Массив – это особый подвид объектов.*

let arr = new Array(); let arr = [];

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

Получение последних элементов массива:
fruits[fruits.length - 1] fruits.at (-1)

Методы:
slice: Создает новый массив, содержащий копию части исходного массива. Можно указать начальный и конечный индексы для выбора нужной части массива.
const arr = [1, 2, 3, 4, 5]; const slicedArr = arr.slice(1, 4); console.log(slicedArr); // Вывод: [2, 3, 4]
splice: Изменяет содержимое массива, удаляя, заменяя или добавляя элементы на указанной позиции.
const arr = [1, 2, 3, 4, 5]; arr.splice(2, 2, 'a', 'b'); // индекс, с которого начинается изменение массива, количество элементов, которые нужно удалить из массива, элементы, которые нужно добавить в массив на место удаленных элементов console.log(arr); // Вывод: [1, 2, 'a', 'b', 5]
push добавляет элемент в конец.
pop удаляет последний элемент.
unshift добавляет элемент в начало массива:
shift удаляет элемент в начале, сдвигая очередь, так что второй элемент становится первым.
Методы push и unshift могут добавлять сразу несколько элементов. Методы push/pop выполняются быстро, а методы shift/unshift – медленно, потому что работать с концом массива всегда быстрее, чем с началом.
Используйте indexOf(), чтобы найти, под каким индексом хранится элемент.
Используйте includes(), чтобы проверить, что элемент есть в массиве
concat: Объединяет два или более массивов и возвращает новый массив, содержащий элементы из всех объединенных массивов.
forEach: Выполняет указанную функцию один раз для каждого элемента массива.
map: Создает новый массив, содержащий результаты вызова указанной функции для каждого элемента исходного массива.

Многомерные массивы
Массивы могут содержать элементы, которые тоже являются массивами. Это можно использовать для создания многомерных массивов, например, для хранения матриц:
let matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]; alert( matrix[1][1] ); // 5, центральный элемент

В современном JavaScript очень популярна деструктуризация массивов. Этот подход позволяет создавать переменные из элементов массива в одну строку:
const catProfile = [ 'Maru', 'Scottish Fold', true, 'https://youtu.be/ChignoxJHXc' ] const [name, breed] = catProfile console.log(name) // Maru

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Тип данных Object

A

Объект (object) — это особый тип данных, он единственный не является примитивом в JS.
Каждое свойство состоит из ключа и значения. Ключ может быть строкой или символом, а значение может быть любым.
Чаще всего объекты создают с помощью литеральной записи.
const cat = {}
Создать объект также можно с помощью конструктора Object. Это объектно-ориентированный стиль программирования:
const book = new Object({ title: 'Война и мир', author: 'Лев Толстой' })

Чтение свойств с помощью точки:
console.log(На полке стоит «${book.title}») // На полке стоит «Война и мир»
Альтернативно для чтения можно использовать квадратные скобки:
console.log(На полке стоит «${book[‘title’]}»)

Для добавления и изменения свойств используется одинаковый синтаксис. Нужно обратиться к свойству и присвоить в него значение с помощью стандартного оператора присваивания =.
Если свойство не существует, оно будет создано:
const book = { title: 'Капитанская дочка' } book.author = 'А.С.Пушкин' // добавляем новое свойство book.title = 'Сказка о царе Салтане' // изменяем существующее console.log(book) // { title: 'Сказка о царе Салтане', author: 'А.С.Пушкин'} delete book['author'] delete book.title

Чаще всего свойства не удаляют, а сбрасывают значение, устанавливая undefined или подходящее по смыслу:
book.title = undefined book['author'] = undefined
Для проверки, есть ли свойство у объекта, используйте оператор in:
const user = { firstName: 'Марина', username: 'zloyDuh' } console.log('firstName' in user) // true console.log('age' in user) // false

Преобразование в массив:
Object.keys(user) = [“name”, “age”]
Object.values(user) = [“John”, 30]
Object.entries(user) = [ [“name”,”John”], [“age”,30] ]
Преобразование обратно в объект:
Object.fromEntries

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Методы объектов

A

Статические методы объекта - методы, которые предварительно определены и вызываются в классе объектов.
Object.keys(obj) – возвращает массив ключей.
Object.values(obj) – возвращает массив значений.
Object.entries(obj) – возвращает массив пар [ключ, значение].

Обойти их
for (let value of Object.values(user)) {
alert(value); // John, затем 30
}

Object.fromEntries(array) - преобразует массив в объект
// преобразовать в массив, затем map, затем fromEntries обратно объект

Object.fromEntries( Object.entries(prices).map(([key, value]) => [key, value * 2]) );

Методы экземпляра — это методы, встроенные в объекты, которые работают с конкретным экземпляром объекта, а не с классом объекта.
Object.prototype.hasOwnProperty() возвращает логическое значение, указывающее, имеет ли объект указанное свойство.
const object1 = {};
object1.property1 = 42;
console.log(object1.hasOwnProperty(‘property1’));
// Expected output: true

Метод Object.create() создаёт новый объект с указанным прототипом и свойствами.
Метод Object.assign() используется для копирования перечисляемых и собственных свойств из одного или более исходных объектов в целевой объект. После копирования он возвращает целевой объект.
var o1 = { a: 1 };
var o2 = { [Symbol(‘foo’)]: 2 };
var obj = Object.assign({}, o1, o2);
console.log(obj); // { a: 1, [Symbol(“foo”)]: 2 }

Object.preventExtensions(объект) предотвращает добавление новых свойств к объекту (то есть, предотвращает расширение этого объекта в будущем).
Object.isExtensible(объект) определяет, является ли объект расширяемым (то есть, можно ли к нему добавлять новые свойства).

Метод Object.freeze() предотвращает модификацию свойств и значений объекта и добавление или удаление свойств объекта.
Метод Object.isFrozen() позволяет определить, был ли объект заморожен или нет, и возвращает логическое значение.

Метод Object.seal() предотвращает добавление новых свойств объекта, но позволяет изменять существующие свойства.
// Возвращает true, если объект “запечатан”
Object.isSealed(объект) определяет, является ли объект запечатанным.

Метод Object.getPrototypeOf() используется для получения внутреннего скрытого [[Prototype]] объекта, также доступного через свойство __proto__.
Существует также связанный с ним метод Object.setPrototypeOf(), который добавляет один прототип к другому объекту. Но вместо этого рекомендуется использовать Object.create(), поскольку он быстрее и эффективнее.

Метод Object.defineProperty() определяет новое или изменяет существующее свойство непосредственно на объекте, возвращая этот объект.
// Добавить или изменить свойство объекта
Object.defineProperty(объект, свойство, описатель)
Object.defineProperty(объект, свойство, {value : значение})
Object.defineProperty(person, “language”, {writable:false}); // делаем свойство language только для чтения

// Добавить или изменить несколько свойств объекта
Object.defineProperties(объект, описатель)

  • writable : true // Значение свойства можно изменять
  • enumerable : true // Свойство может перечисляться
  • configurable : true // Свойство может настраиваться

// Определение геттера
get: function() {
return language
}
// Определение сеттера
set: function(value) {
language = value
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Полифил map

A

// Добавляем новый метод myMap в прототип массива
Array.prototype.myMap = function(callback) {
// Проверяем, что this является массивом или строкой
// Если тип неверный, выбрасываем ошибку TypeError
if (!this instanceof Array || !this instanceof String) {
throw new TypeError(‘Wrong type’);
}
// Проверяем, что callback является функцией
// Если не является, выбрасываем ошибку TypeError
if (typeof callback !== “function”) {
throw new TypeError(‘Callback isn't function’);
}
const result = [];
// Проходим по каждому элементу исходного массива/строки
// Вызываем callback для каждого элемента и добавляем результат в новый массив
for (let i = 0; i < this.length; i += 1) {
result.push(callback(this[i], i, this));
}
return result;
};

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Полифил reduce

A

Метод reduce применяет функцию reducer к каждому элементу массива (слева-направо), возвращая одно результирующее значение.
Пример reduce:
let people = [
{ name: “Ira”, age: 10 },
{ name: “Kira”, age: 20 },
{ name: “Lira”, age: 30 },
{ name: “Vira”, age: 40 },
];
const amount = people.reduce((total, elem) => (total += elem.age), 0); //100

Полифил reduce:

// Добавляем новый метод myReduce в прототип массива
Array.prototype.myReduce = function(callback, accumulator) {
// Проверяем, что this является массивом или строкой
// Если тип неверный, выбрасываем ошибку TypeError
if (!this instanceof Array || !this instanceof String) {
throw new TypeError(‘Wrong type’);
}
// Проверяем, что callback является функцией
// Если не является, выбрасываем ошибку TypeError
if (typeof callback !== “function”) {
throw new TypeError(‘Callback isn't function’);
}

// Инициализируем аккумулятор значением, переданным в качестве аргумента или первым элементом массива
// Устанавливаем начальное значение индекса в зависимости от наличия аргумента аккумулятора
let acc = arguments.length > 1 ? accumulator : this[0];
let iStart = arguments.length > 1 ? 0 : 1;

// Проходим по каждому элементу массива/строки, начиная с определенного индекса
// Вызываем callback с текущим значением аккумулятора, текущим элементом, индексом и самим массивом
for (let i = iStart; i < this.length; i += 1) {
acc = callback(acc, this[i], i, this);
}
return acc;
};

let arr = [0, 1, 3, 5, 7, 8];
const myReduceResult = arr.myReduce((acc, curr, idx, arr) => {
// Используем myReduce для расчета суммы элементов массива
acc += curr;
return acc;
});
console.log(myReduceResult);
// Вывод: 24

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Что такое Big-О

A

В программировании Big-О показывает эффективность конкретного алгоритма. Всегда рассматривается наихудший вариант расчета. Конcтанты откидываются.

Одними из самых часто встречаемых сложностей являются:

  • О(1) - самый эффективный. Вывод 10 элемента в массиве, т.к. это делается по индексу, нам не важно 100 там элементов или миллион, на задачу требуется всегда один шаг. Также хэш-таблицы имеют эту сложность для поиска, индексации и добавления.
  • O(log n) - поиск в отсортированном массиве через бинарный поиск. Сюда относятся все функции, где входящий массив или структура данных делится пополам для поиска.
  • O(n) - поиск элемента в несортированном массиве - для получения результата, вам придется перебрать весь список. Или суммирование элементов массива - тоже нужно пройти все элементы. Чем больше массив, тем больше операций. Можно сказать «сложность порядка n (order n)». Так же такой тип алгоритмов называют «линейными» или что алгоритм «линейно масштабируется». Интересно: Если мы знаем, что массив начинается с 1, отсортирован и не имеет пропусков, для суммирования можно применить формулу S = n(n+1)/2 (где n последний элемент массива) - такая запись будет уже более эффективной O(1).
  • O(n log n) - n раз logn. Как пример сортировка слиянием. Получается O(n * log n), или O(n log n).
  • O(n²) - пузырьковая сортировка, поиск дублей в цикле, который в другом цикле. Массив из 4 элементов требует 16 шагов, массив из 10 элементов – 100 шагов.
  • O(2^n) - поиск всех подмножеств массива. Каждый элемент множества может быть либо включен, либо исключен из подмножества. Набор из четырех элементов [A,B,C,D, E] будет иметь 2^5 или 32 подмножеств.
    [A], [B], [C], [D], [E]
    [A,B], [A,C], [A,D], [A, E], [B,C], [B,D], [C,D] и т.д.
  • O(n!) - самый неэффективный. К примеру, поиск всех возможных вариантов расположения элементов в массиве [A, B, C, D] потребует 4! или 24 шага.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Что такое bind, когда он используется, полифил bind

A

Метод bind() является одним из методов встроенного объекта функции в JavaScript. Он используется для создания новой функции, привязанной к определенному контексту выполнения. Это позволяет явно указать значение this внутри функции и также позволяет привязать предопределенные аргументы.
Привязанная функция, созданная с помощью bind(), не вызывается немедленно. Вместо этого, она возвращается, чтобы ее можно было вызвать позднее.

bind() принимает один или более аргументов:
- thisArg: Объект, который будет использоваться в качестве значения this внутри функции, которая будет создана при вызове bind().
- аргументы: Предопределенные аргументы, которые будут переданы в функцию при вызове.

Пример использования bind():
const obj = { x: 42, getY: function() { return this.x; } }; const boundGetY = obj.getY.bind(obj); // Создаем новую функцию, в которой this будет ссылаться на объект obj console.log(boundGetY()); // Вывод: 42 const anotherObj = { x: 99 }; const boundGetY2 = obj.getY.bind(anotherObj); console.log(boundGetY2()); // Вывод: 99

Function.prototype.myBind = function (...args) { var callback = this, ctx = args.splice(1); return function (...a) { //параметр …a содержит все аргументы, которые можно передать result2()методу. callback.call(args[0], ...[...ctx, ...a]); // args[0] является первым аргументом, переданным myBind()методу (то есть объекту myName), // ctx содержит все остальные аргументы, переданные нашему myBind()методу }; }; const result2 = printName.myBind(myName, "Palia"); result2("India");

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Что такое call, когда он используется, полифил call

A

call() - это метод встроенного объекта функции в JavaScript. Он используется для вызова функции, устанавливая указанное значение this и передавая аргументы в виде списка. При использовании call(), функция вызывается с установленным значением this, которое передается в thisArg, и аргументами, которые передаются в списке после thisArg.

Синтаксис метода call():
function.call(thisArg, arg1, arg2, ...)

  • thisArg: Объект, который будет использоваться в качестве значения this внутри функции.
  • arg1, arg2, …: Аргументы, которые будут переданы в функцию при вызове.

Пример использования call():
const person1 = { name: 'Alice', greeting: function() { return 'Hello, ' + this.name + '!'; } }; const person2 = { name: 'Bob' }; console.log(person1.greeting.call(person2)); // Output: Hello, Bob!
Полифил:
Function.prototype.myCall = function (context, ...args) { let currentContext = context || globalThis; let randomProp = Math.random(); while (currentContext[randomProp] !== undefined) { randomProp = Math.random(); } // генерируем случайное свойство, используя Math.random,чтобы убедиться, что свойство уникально. currentContext[randomProp] = this; let result = currentContext[randomProp](...args); delete currentContext[randomProp]; return result; }; printName.myCall(myName, "Palia", "India");

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Объект Date

A

Объект JavaScript Date — это глобальный объект, который используется для работы с датами и временем. Объекты Date основаны на значении времени, которое представляет собой количество миллисекунд с 1 января 1970 года по всемирному координированному времени.
Важно: при установке месяца, отчёт идёт с 0, где 0 — это январь. При выводе дня недели возвращаемое значение также начинается с 0 и означает воскресенье.

Основные методы
new Date() создаёт экземпляр Date с текущей датой и временем.
new Date(значение) создаёт Date с переданным значением времени. Значение должно быть в формате, который распознается методом Date.parse(), то есть быть совместимым с IETF RFC 2822 или с ISO8601.
new Date(год, месяц, день, часы, минуты, секунды, миллисекунды) создаёт класс Date в местной часовой зоне. Год и месяц являются обязательными параметрами. Остальные параметры, начиная с часов, будут по умолчанию равны 0, а день — 1.
new Date(миллисекунды) создаёт Date со временем в миллисекундах. Количество миллисекунд измеряется с 1 января 1970 года UTC.
getFullYear() — возвращает год;
getMonth() — возвращает месяц с 0 до 11;
getDate() — возвращает день месяца с 1 до 31;
getDay() — возвращает порядковый номер дня недели с 0 до 6;
getHours() — возвращает часы с 0 до 23;
getMinutes() - возвращает минуты от 0 до 59;
getSeconds() - возвращает секунды от 0 до 59;
getMilliseconds() - возвращает миллисекунды от 0 до 999.
getTime() возвращает значение в миллисекундах, прошедших с 1 января 1970 года, соответствующее указанной дате по UTC.
getTimezoneOffset() возвращает смещение в минутах между текущей часовой зоной и UTC.
setFullYear(год, месяц, день) устанавливает год, значения месяца и дня необязательны.
setMonth(месяц, день) устанавливает месяц, передавать день необязательно.
setDate(день) устанавливает день месяца.
setHours(часы, минуты, секунды, миллисекунды) устанавливает часы. Значения минут, секунд, миллисекунд необязательны.
setMinutes(минуты, секунды, миллисекунды) - устанавливает минуты. Секунды и миллисекунды необязательны.
setSeconds(секунды, миллисекунды) устанавливает секунды. Миллисекунды передавать необязательно.
setMilliseconds(миллисекунды) - устанавливает миллисекунды.
Для UTC аналогичные методы, только добавляем UTC после set. Например, setUTCMilliseconds(миллисекунды).
И метод, который относится только к UTC:
setTime(значение) устанавливает значение, которое равно количеству миллисекунд, прошедших с 1 января 1970 года.

Метод Date.parse(значение) используется для разбора (ещё говорят парсинга) строкового представления даты.
Возвращает значение, равное количеству миллисекунд, прошедших с 1 января 1970 года.

Для отображения Date в различных форматах существует метод toLocaleDateString(локаль, опции).
Локаль — это необязательный параметр, который является строкой или массивом строк с языковой меткой BCP 47.
Например, en-US или de-DE. Локаль хранит региональные настройки о формате дат, номеров, адресов.
Опции — необязательный параметр с объектом настроек. Доступные свойства:
localeMatcher — алгоритм поиска локали, используется для выбора подходящей локали. Принимает значения lookup или best fit. По умолчанию best fit.
timeZone — значение используемого часовой зоны. Все браузеры должны принимать значение UTC, значение по умолчанию равно значению часовой зоны среды выполнения. Формат принимаемого значения может различаться в различных браузерах.
hour12 — значение, которое определяет, использовать ли 12-часовой формат вывода. Принимает true или false.
formatMatcher — алгоритм поиска формата, используется для выбора формата отображения. Принимает значения basic или best fit. По умолчанию best fit.
timeZoneName — формат названия часовой зоны. Принимает long или short.
weekday — значение дня недели. Принимает narrow, short и long.
era — значение эры. Принимает narrow, short и long.
year — значение года. Принимает numeric и 2-digit.
month — значения месяца. Принимает numeric, 2-digit, narrow, short и long.
day — значения дня. Принимает numeric и 2-digit.
hour — значения часа. Принимает numeric и 2-digit.
minute — значения минут. Принимает numeric и 2-digit.
second — значения секунд. Принимает numeric и 2-digit.
Браузеры обязаны поддерживать следующие наборы настроек отображения:
weekday, year, month, day, hour, minute, second weekday, year, month, day year, month, day year, month month, day hour, minute, second hour, minute

Date.now() — метод, который возвращает текущее время в миллисекундах, прошедших с 1 января 1970 года UTC.
Если вам не хватает функциональности, представленной классом Date, например, недостаточно его возможностей форматирования или парсинга, то можно посмотреть в сторону библиотек day.js или date-fns.

В следующей таблице перечислены стандартные свойства объекта Date.

prototype - Позволяет добавлять новые свойства и методы к объекту Date.
Примечание. У каждого объекта в JavaScript есть свойство конструктора, которое ссылается на функцию конструктора, которая использовалась для создания экземпляра этого объекта.

В следующей таблице перечислены стандартные методы объекта Date.
- getDate(): Возвращает день месяца (от 1 до 31).
- getDay(): Возвращает день недели (от 0 до 6).
- getFullYear(): Возвращает год (четыре цифры).
- getHours(): Возвращает час (от 0 до 23).
- getMilliseconds(): Возвращает миллисекунды (от 0 до 999).
- getMinutes(): Возвращает минуты (от 0 до 59).
- getMonth(): Возвращает месяц (от 0 до 11).
- getSeconds(): Возвращает секунды (от 0 до 59).
- getTime(): Возвращает количество миллисекунд, прошедших с полуночи 1 января 1970 года.
- getTimezoneOffset(): Возвращает разницу во времени между временем UTC и местным временем в минутах.
- getUTCDate(): Возвращает день месяца по всемирному времени (от 1 до 31).
- getUTCDay(): Возвращает день недели по всемирному времени (от 0 до 6).
- getUTCFullYear(): Возвращает год по всемирному времени.
- getUTCHours(): Возвращает час по всемирному времени (от 0 до 23).
- getUTCMilliseconds(): Возвращает миллисекунды по всемирному времени (от 0 до 999).
- getUTCMinutes(): Возвращает минуты по всемирному времени (от 0 до 59).
- getUTCMonth(): Возвращает месяц по всемирному времени (от 0 до 11).
- getUTCSeconds(): Возвращает секунды по всемирному времени (от 0 до 59).

  • now() - Возвращает количество миллисекунд, прошедших с полуночи 1 января 1970 года.
  • parse() - Разбирает строку даты и возвращает количество миллисекунд с 1 января 1970 года.
  • setDate() - Устанавливает день месяца объекта даты.
  • setFullYear() - Устанавливает полный год объекта даты.
  • setHours() - Устанавливает часы объекта даты.
  • setMilliseconds() - Устанавливает миллисекунды объекта даты.
  • setMinutes() - Устанавливает минуты объекта даты.
  • setMonth() - Устанавливает месяц объекта даты.
  • setSeconds() - Устанавливает секунды объекта даты.
  • setTime() - Устанавливает дату на указанное количество миллисекунд после/до 1 января 1970 года.
  • setUTCDate() - Устанавливает день месяца объекта даты по всемирному времени
  • setUTCFullYear() - Устанавливает год объекта даты по всемирному времени.
  • setUTCHours() - Устанавливает часы объекта даты по всемирному времени.
  • setUTCMilliseconds() - Устанавливает миллисекунды объекта даты по всемирному времени.
  • setUTCMinutes() - Установите минуты объекта даты по всемирному времени.
  • setUTCMonth() - Устанавливает месяц объекта даты по всемирному времени.
  • setUTCSeconds() - Установите секунды объекта даты по всемирному времени.
  • toDateString() - Преобразует часть даты объекта Date в удобочитаемую форму.
  • toISOString(): Возвращает дату в виде строки, отформатированной в соответствии со стандартом ISO.
  • toJSON(): Возвращает дату в виде строки в формате даты JSON.
  • toLocaleDateString(): Возвращает часть даты объекта Date в виде строки локального формата.
  • toLocaleTimeString(): Возвращает временную часть объекта Date в виде строки локального формата.
  • toLocaleString(): Преобразует объект Date в строку локального формата.
  • toString(): Преобразует объект Date в строку.
  • toTimeString(): Преобразует временную часть объекта Date в строку.
  • toUTCString(): Преобразует объект Date в строку по всемирному времени.
  • UTC(): Возвращает количество миллисекунд в объекте Date с 00:00:00 (полночь) 1 января 1970 года по всемирному времени.
  • valueOf(): Возвращает примитивное значение объекта Date.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Что такое DOM Events?

A

Событие – это сигнал от браузера о том, что что-то произошло. Все DOM-узлы подают такие сигналы (хотя события бывают и не только в DOM).

События мыши:
- click – происходит, когда кликнули на элемент левой кнопкой мыши (на устройствах с сенсорными экранами оно происходит при касании).
- contextmenu – происходит, когда кликнули на элемент правой кнопкой мыши.
- mouseover / mouseout – когда мышь наводится на / покидает элемент.
- mousedown / mouseup – когда нажали / отжали кнопку мыши на элементе.
- mousemove – при движении мыши.

События на элементах управления:
- submit – пользователь отправил форму <form>.
- focus – пользователь фокусируется на элементе, например нажимает на <input></input>.

Клавиатурные события:
- keydown и keyup – когда пользователь нажимает / отпускает клавишу.

События документа:
- DOMContentLoaded – когда HTML загружен и обработан, DOM документа полностью построен и доступен.

CSS events:
- transitionend – когда CSS-анимация завершена.

Существует множество других событий.

Событию можно назначить обработчик, то есть функцию, которая сработает, как только событие произошло.
Именно благодаря обработчикам JavaScript-код может реагировать на действия пользователя.
1. Обработчик может быть назначен прямо в разметке, в атрибуте, который называется on<событие>.
<input value="Нажми меня" onclick="alert('Клик!')" type="button"
2. Можно назначать обработчик в JS, используя свойство DOM-элемента on<событие>.
elem.onclick = function() { alert('Спасибо'); };
Так как у элемента DOM может быть только одно
свойство с именем onclick, то назначить более одного обработчика так нельзя.
3. И последний и более гибкий способ: addEventListener и removeEventListener. С помощью него можно повесить более одного обработчика на одно событие, а также можно удалить обработчик, вызвав его и передав ту же функцию. Есть несколько типов событий, которые работают только через него, к примеру transitionend и DOMContentLoaded. Также addEventListener поддерживает объекты в качестве обработчиков событий. В этом случае вызывается метод объекта handleEvent.
Не важно, как вы назначаете обработчик – он получает объект события первым аргументом. Этот объект содержит подробности о том, что произошло.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Расскажи про Form и Input Events

A

Form и Input Events - это события, которые позволяют отслеживать и реагировать на действия пользователя, связанные с отправкой формы, изменением значений полей ввода и другими взаимодействиями с элементами форм и ввода.

Некоторые из наиболее часто используемых событий форм и ввода включают:

  • submit: Событие submit возникает, когда пользователь отправляет форму. Это может произойти, например, при нажатии на кнопку отправки или использовании клавиши Enter в текстовом поле. Для отслеживания отправки формы вы можете прослушивать событие submit на элементе.
  • input: Событие input возникает, когда значение в поле ввода изменяется пользователем. Это может быть поле ввода текста, чекбокс, переключатель и другие элементы. Событие input позволяет реагировать на моментальные изменения значения в поле ввода.
  • change: Событие change возникает, когда значение в поле ввода изменяется и пользователь уводит фокус с элемента. Это позволяет отслеживать изменения значения и принимать соответствующие действия, когда пользователь закончил ввод.
  • cut: Событие cut возникает, когда пользователь вырезает выделенный текст или другой выделенный контент с использованием горячих клавиш или контекстного меню. Вы можете использовать это событие для выполнения дополнительных действий при вырезании данных пользователем. Это событие можно предотвратить, чтобы запретить вырезание содержимого.
  • copy: Событие copy возникает, когда пользователь копирует выделенный текст или другой выделенный контент с использованием горячих клавиш или контекстного меню. Подобно событию cut, вы можете использовать эту возможность для выполнения дополнительных действий при копировании данных пользователем. Можно предотвратить это действие, чтобы запретить копирование содержимого.
  • paste: Событие paste возникает, когда пользователь вставляет данные из буфера обмена в поле ввода или другой элемент на странице. Вы можете использовать это событие для выполнения дополнительной обработки данных, вставленных пользователем. Можно предотвратить вставку данных, чтобы запретить вставку содержимого.
  • focus: Событие focus возникает, когда элемент ввода или другой элемент получает фокус. Например, когда пользователь щелкает на текстовое поле.
  • blur: Событие blur возникает, когда элемент ввода или другой элемент теряет фокус. Например, когда пользователь переключается на другой элемент или щелкает вне текстового поля.
  • select: Событие select возникает, когда пользователь выбирает (выделяет) текст в элементе ввода или другом элементе на странице.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

Как перебрать ключи и значения объекта в JavaScript?

A
  1. Цикл for...in используется для перебора ключей объектов, массивов и строк.
  2. Метод Object.keys() возвращает массив ключей объекта.
  3. Метод Object.values() возвращает значения всех свойств объекта в виде массива.
  4. Метод Object.entries() возвращает массив пар ключ-значение объекта.

Метод Object.keys() был добавлен в ES6, тогда как Object.entries() и Object.values() методы были добавлены в ES8. Эти методы преобразуют объект в массив, а затем используют методы цикла массива для перебора этого массива.

Самый простой и популярный способ перебора ключей и значений объекта — использование for…in цикла:

const birds = { 
owl: '🦉', 
eagle: '🦅', 
duck: '🦆', 
chicken: '🐔' 
}
for (const key in birds) { 
 console.log(`${key} -> ${birds[key]}`) 
}
// owl -> 🦉 
// eagle -> 🦅 
// duck -> 🦆 
// chicken -> 🐔

Единственная проблема с for…in циклом заключается в том, что он перебирает свойства в цепочке прототипов. Поскольку объект JavaScript наследует свойства своего прототипа , for…in цикл также будет перебирать эти свойства. Однако вы можете использовать этот hasOwnProperty() метод для исключения унаследованных свойств :
for (const key in birds) { if (birds.hasOwnProperty(key)) { console.log(${key} -> ${birds[key]}) } }

Метод Object.keys() принимает объект в качестве входных данных и возвращает массив имен собственных перечисляемых свойств объекта:
const birds = { owl: '🦉', eagle: '🦅', duck: '🦆', chicken: '🐔' } const keys = Object.keys(birds) console.log(keys) // [ 'owl', 'eagle', 'duck', 'chicken' ]

Теперь мы можем использовать forEach()цикл для перебора массива и получения значения каждого свойства:

keys.forEach(key => { console.log(${key} -> ${birds[key]}) }) // owl -> 🦉 // eagle -> 🦅 // duck -> 🦆 // chicken -> 🐔

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Как остановить распространение событий ( stopPropagation() / stopImmediatePropagation() )?

A

Метод stopPropagation() интерфейса Event предотвращает дальнейшее распространение текущего события на этапах захвата и всплытия. Однако это не предотвращает появление поведения по умолчанию; например, клики по ссылкам все еще обрабатываются. Если вы хотите остановить такое поведение, используйте метод preventDefault(). Это также не препятствует немедленному распространению на другие обработчики событий. Если вы хотите остановить их, используйте метод stopImmediatePropagation().

Ниже приведен пример кода, который демонстрирует использование метода stopPropagation():

const outerElement = document.querySelector(“#outer”);
const innerElement = document.querySelector(“#inner”);
outerElement.addEventListener(“click”, function(event) {
console.log(“Внешний элемент”);
});

innerElement.addEventListener(“click”, function(event) {
console.log(“Внутренний элемент”);
event.stopPropagation();
});

innerElement.click();
// Вывод:
// Внутренний элемент
// Внешний элемент

Объяснение: При клике на внутреннем элементе inner, обработчик события вызывает event.stopPropagation(), что приводит к прекращению распространения события дальше по вложенным элементам. В результате сначала вызывается обработчик внутреннего элемента inner, а затем обработчик внешнего элемента outer.

Метод stopImmediatePropagation() интерфейса Event предотвращает вызов других слушателей того же события. Если к одному и тому же элементу для одного и того же типа события прикреплено несколько слушателей, они вызываются в том порядке, в котором были добавлены. Если stopImmediatePropagation() вызывается во время одного такого вызова, остальные прослушиватели вызываться не будут.

Ниже приведен пример кода, который демонстрирует использование метода stopImmediatePropagation():

const button = document.querySelector(“#myButton”);
button.addEventListener(“click”, function(event) {
console.log(“Обработчик клика 1”);
event.stopImmediatePropagation();
});

button.addEventListener(“click”, function(event) {
console.log(“Обработчик клика 2”);
});

button.addEventListener(“click”, function(event) {
console.log(“Обработчик клика 3”);
});

button.click();
// Вывод:
// Обработчик клика 1
Объяснение: При клике на кнопке myButton, первый обработчик события прерывает дальнейшее распространение события, вызывая метод event.stopImmediatePropagation(). Поэтому второй и третий обработчики не выполняются, и в консоли выводится только сообщение из первого обработчика.

Итого: stopPropagation() позволяет выполнять другие обработчики событий для того же элемента, но stopImmediatePropagation() предотвращает это. stopPropagation() и stopImmediatePropagation() предотвращают выполнение обработчиков событий на этапах захвата и всплытия.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q

Расскажи про HTMLCollection и NodeList

A

HTMLCollection и NodeList — это очень похожие на массив коллекции. Они хранят элементы веб-страницы (узлы DOM). NodeList может хранить любые типы узлов, а HTMLCollection — только узлы HTML элементов. К элементам коллекций можно обращаться по индексу, но у них нет привычных методов массива. HTMLCollection возвращают методы getElementsByTagName() и getElementsByClassName(). NodeList возвращают метод querySelectorAll() и свойство childNodes.

Полученная один раз HTMLCollection всегда остаётся актуальной — JavaScript будет обновлять её в случае, если на странице появляется подходящий элемент. Поэтому HTMLCollection называют «живой» коллекцией.

NodeList работает почти так же, как и HTMLCollection.

Разница:
1. NodeList может хранить любые типы узлов, например текстовые узлы и комментарии, а HTMLCollection — только узлы HTML элементов.
2. HTMLCollection позволяет обращаться к элементам не только по индексу, но и по имени с помощью метода namedItem.
3. NodeList может быть не только «живой» коллекцией, но и статической. Такая коллекция не обновляется при появлении на странице новых элементов.

«Живой» NodeList возвращают метод getElementsByName() и свойство childNodes. Статический NodeList возвращает метод querySelectorAll().

Если очень нужны методы массива, то преобразуйте HTMLCollection или NodeList в массив с помощью Array.from().

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
26
Q

Интернационализация в JavaScript

A

Общая проблема строк, дат, чисел в JavaScript – они «не в курсе» языка и особенностей стран, где находится посетитель.
- Строки- при сравнении сравниваются коды символов, а это неправильно, к примеру, в русском языке оказывается, что “ё” > “я”, хотя я – последняя буква алфавита и это она должна быть больше любой другой.
- Даты в разных странах принята разная запись дат. Где-то пишут 31.12.2014 (Россия), а где-то 12/31/2014 (США), где-то иначе.
- Числа в одних странах выводятся цифрами, в других – иероглифами, длинные числа разделяются где-то пробелом, где-то запятой.
Все современные браузеры, кроме IE10 (но есть библиотеки и для него) поддерживают стандарт ECMA 402, предназначенный решить эти проблемы навсегда.

Интерфейс Intl является встроенным объектом в JavaScript, предоставляющим поддержку интернационализации (i18n) и локализации (l10n) при работе с различными языками и региональными настройками. Он предоставляет различные функциональности для форматирования чисел, дат, времени, валюты и текста с учетом локализации.

Вот некоторые из хорошо известных возможностей Intl в JavaScript:

  • Intl.Collator: умеет правильно сравнивать и сортировать строки.
    const names = ['Иван', 'Алексей', 'Ян', 'Джон', 'Élodie']; const collator = new Intl.Collator('ru', { sensitivity: 'base' }); const sortedNames = names.sort(collator.compare); console.log(sortedNames); // ["Алексей", "Джон", "Иван", "Élodie", "Ян"]
  • Intl.NumberFormat: позволяет форматировать числа в соответствии с языковыми представлениями и локальными настройками. С помощью этого класса вы можете задать количество десятичных знаков, разделители тысячных и дробных частей, а также символы для обозначения валюты.
    const number = 12345.6789; const formattedNumber = new Intl.NumberFormat('en-US', { style: 'decimal' }).format(number); console.log(formattedNumber); // "12,345.6789"
  • Intl.DateTimeFormat: позволяет форматировать даты и времена с учетом языковых представлений и локальных настроек. С помощью этого класса вы можете установить формат даты и времени, использовать определенные календарные системы и часовые пояса.
    const date = new Date(); const formattedDate = new Intl.DateTimeFormat('en-US', { dateStyle: 'full', timeStyle: 'short' }).format(date); console.log(formattedDate); // "Friday, October 29, 2021 at 2:30 PM"
  • Intl.ListFormat: предоставляет возможность форматирования списков значений с использованием языковых представлений. Он позволяет задать разделитель между элементами списка и перед последним элементом списка для более понятного отображения.
    const fruits = ['яблоко', 'банан', 'киви', 'апельсин']; const listFormat = new Intl.ListFormat('ru', { style: 'long', type: 'conjunction' }); const formattedList = listFormat.format(fruits); console.log(formattedList); // "яблоко, банан, киви и апельсин"
  • Intl.PluralRules: позволяет определить правила склонения для различных числовых значений в соответствии с языковыми представлениями. Это полезно при отображении правильной формы слова для разных числовых значений, таких как единственное число, множественное число и другие.
    const count = 5; const pluralRules = new Intl.PluralRules('en'); const plural = pluralRules.select(count); const message = У вас ${count} ${plural} яблок${plural === ‘one’ ? ‘о’ : ‘а’}; console.log(message); // "У вас 5 яблок"
  • Intl.RelativeTimeFormat: позволяет форматировать относительное время (например, “5 минут назад” или “через 3 дня”) с учетом языковых представлений. Это полезно для создания дружественных для пользователя сообщений времени.
    const minutesAgo = -5; const relativeTimeFormat = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }); const formattedRelativeTime = relativeTimeFormat.format(minutesAgo, 'minute'); console.log(formattedRelativeTime); // "5 minutes ago"

Все эти методы при запуске создают соответствующий объект Intl.* и передают ему опции, можно рассматривать их как укороченные варианты вызова.

Локаль – первый и самый важный аргумент всех методов, связанных с интернационализацией. Локаль описывается строкой из трёх компонентов, которые разделяются дефисом:
- Код языка.
- Код способа записи.
- Код страны.

На практике не всегда указаны три, обычно меньше:
ru – русский язык, без уточнений.
en-GB – английский язык, используемый в Англии (GB).
en-US – английский язык, используемый в США (US).
zh-Hans-CN – китайский язык (zh), записываемый упрощённой иероглифической письменностью (Hans), используемый в Китае.

Все методы принимают локаль в виде строки или массива, содержащего несколько локалей в порядке предпочтения.
Если локаль не указана или undefined – берётся локаль по умолчанию, установленная в окружении (браузере).

Подбор локали localeMatcher
localeMatcher – вспомогательная настройка, которую тоже можно везде указать, она определяет способ подбора локали, если желаемая недоступна.
У него два значения:
1. “lookup” – означает простейший порядок поиска путём обрезания суффикса, например zh-Hans-CN → zh-Hans → zh → локаль по умолчанию.
2. “best fit” – использует встроенные алгоритмы и предпочтения браузера (или другого окружения) для выбора подходящей локали.
По умолчанию стоит “best fit”.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
27
Q

Local Storage vs Session Storage vs Cookie

A

Local Storage (локальное хранилище)
- Хранит данные бессрочно.
- Очищается только с помощью JavaScript или очистки кэша браузера.
- Хранит данные объёмом до 5 МБ, это самый большой объём из трёх вариантов хранилища.
- Не поддерживается старыми браузерами, например, IE 7 и ниже.
- Работает по правилу ограничения домена (same origin policy). То есть сохранённые данные доступны только для одного источника.
- браузеры на основе движка WebKit, например Safari, очищают localStorage, если к нему не обращались в течение 7 дней

Session Storage (сессионное хранилище)
- Хранит данные, пока продолжается текущая сессия. Когда пользователь закрывает браузер, данные становятся недоступными.
- Используется контекст браузера верхнего уровня, поэтому каждая вкладка браузера хранит уникальные данные.
- Объём данных больше чем в Cookie.
- Не поддерживается старыми браузерами, например, IE 7 и ниже.

Cookie
- Хранит данные, которые можно передавать на сервер через заголовки. Локальное и сессионное хранилище доступны только на клиентской стороне.
- Срок хранения устанавливается при создании cookie.
- Объём данных не превышает 4 Кбайт.
- Cookie могут быть защищёнными, в этом случае их содержимое нельзя получить на стороне клиента. Это важно для аутентификации при хранении пользовательских токенов.

Основные отличия:
1. В отличие от куки, объекты веб-хранилища не отправляются на сервер при каждом запросе. Именно поэтому мы можем хранить гораздо больше данных. Большинство современных браузеров могут выделить как минимум 5 мегабайтов данных (или больше), и этот размер можно поменять в настройках.
2. Ещё одно отличие от куки – сервер не может манипулировать объектами хранилища через HTTP-заголовки. Всё делается при помощи JavaScript.
3. Хранилище привязано к источнику (домен/протокол/порт). Это значит, что разные протоколы или поддомены определяют разные объекты хранилища, и они не могут получить доступ к данным друг друга.

Объекты хранилища localStorage и sessionStorage предоставляют одинаковые методы и свойства:
window.localStorage.setItem('name', 'Дока Дог') - сохранение
window.localStorage.getItem('name') - чтение
window.localStorage.removeItem('name') - удаление
window.localStorage.clear() - очистка хранилища
key(index) – получить ключ на заданной позиции.
length – количество элементов в хранилище.

Иногда нам нужно сохранить не просто текст, а целую структуру данных, и в этом нам поможет JSON.stringify() и после парсим JSON.parse(userJSON). Значения хранятся в виде строк. При попытке сохранения других типов данных, они будут приведены к строке. Например, если записать число, то при чтении нам вернётся число, записанное в строку.

Как видим, интерфейс похож на Map (setItem/getItem/removeItem), но также позволяет получить доступ к элементу по индексу – key(index).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
28
Q

null и undefined различия и сходства

A

Сходства:
- они принадлежат к 7 «примитивам» JS
- являются ложными значениями при преобразовании в булевое значение

Различия:
undefined («неопределенный») представляет собой значение по умолчанию:
- переменной, которой не было присвоено значения, т.е. объявленной, но не инициализированной переменной;
- функции, которая ничего не возвращает явно, например, console.log(1);
- несуществующего свойства объекта.

null — это «значение отсутствия значения». null — это значение, которое присваивается переменной явно.

При сравнении null и undefined мы получаем true, когда используем оператор “==”, и false при использовании оператора “===”.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q

Что такое Object.is?

A

Новая функция для проверки равенства значений. Возвращает true, если значения value1 и value2 равны, иначе false.
Она похожа на обычное строгое равенство ===, но есть отличия:

// Сравнение +0 и -0
alert( Object.is(+0, -0)); // false
alert( +0 === -0 ); // true
// Сравнение с NaN
alert( Object.is(NaN, NaN) ); // true
alert( NaN === NaN ); // false

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
30
Q

Что такое return?

A

return возвращает результат из функции и используется только в функциях. Благодаря return можно использовать результат работы функции где угодно. Например, в условиях или при формировании новых значений. Пример ниже использует функцию с return для проверки условия — действительно ли счёт игрока больше 100:
function checkScore(score) { return score > 100 } const s1 = 10 const s2 = 15 const s3 = 20 if (checkScore(s1)) alert('игрок 1 проходит') if (checkScore(s2)) alert('игрок 2 проходит') if (checkScore(s3)) alert('игрок 3 проходит')

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q

Объект Set

A

Объект Set – это вид коллекции уникальных значений без ключей.

Основные методы:
- new Set(iterable) – создаёт Set, и если в качестве аргумента был предоставлен итерируемый объект (обычно это массив), то копирует его значения в новый Set.
- set.add(value) – добавляет значение (если оно уже есть, то ничего не делает), возвращает тот же объект Set.
- set.delete(value) – удаляет значение, возвращает true, если value было в множестве на момент вызова, иначе false.
- set.has(value) – возвращает true, если значение присутствует в множестве, иначе false.
- set.clear() – удаляет все имеющиеся значения.
- set.size – возвращает количество элементов в множестве.

Пример использования объекта Set:

const set = new Set(); set.add('apple'); set.add('banana'); set.add('apple'); // не будет добавлено, так как значение уже присутствует в множестве console.log(set.size); // 2 console.log(set.has('apple')); // true console.log(set.delete('banana')); // true console.log(set.size); // 1 set.clear(); console.log(set.size); // 0

Перебор объекта Set:
1. for..of:
const set = new Set(['apple', 'banana', 'orange']); for (const value of set) { console.log(value); }

  1. forEach:
    const set = new Set(['apple', 'banana', 'orange']); set.forEach((value, valueAgain, set) => { console.log(value); });

Функция в forEach у объекта Set имеет 3 аргумента: значение value, затем снова то же самое значение valueAgain, и только потом целевой объект set. Это действительно так, значение появляется в списке аргументов дважды. Это сделано для совместимости с объектом Map, в котором колбэк forEach имеет 3 аргумента. Выглядит немного странно, но в некоторых случаях может помочь легко заменить Map на Set и наоборот.

Set имеет те же встроенные методы, что и Map:
- set.keys() – возвращает перебираемый объект для значений.
- set.values() – то же самое, что и set.keys(), присутствует для обратной совместимости с объектом Map.
- set.entries() – возвращает перебираемый объект для пар вида [значение, значение], присутствует для обратной совместимо

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
32
Q

setTimeout и setInterval

A

Мы можем вызвать функцию не в данный момент, а позже, через заданный интервал времени. Это называется «планирование вызова».

Для этого существуют два метода:
- setTimeout позволяет вызвать функцию один раз через определённый интервал времени.
setTimeout(() => alert('Привет'), 1000);
Вызов setTimeout возвращает «идентификатор таймера» timerId, который можно использовать для отмены дальнейшего выполнения.
let timerId = setTimeout(...); clearTimeout(timerId);

  • setInterval позволяет вызывать функцию регулярно, повторяя вызов через определённый интервал времени.
    let timerId = setInterval(() => alert('tick'), 2000);
    Чтобы остановить дальнейшее выполнение функции, необходимо вызвать clearInterval(timerId).
    setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000);

Эти методы не являются частью спецификации JavaScript. Но большинство сред выполнения JS-кода имеют внутренний планировщик и предоставляют доступ к этим методам.

Вложенный setTimeout
let timerId = setTimeout(function tick() { alert('tick'); timerId = setTimeout(tick, 2000); // (*) }, 2000);

Методы setInterval(func, delay, ...args) и setTimeout(func, delay, ...args) позволяют выполнять func регулярно или только один раз после задержки delay, заданной в мс.

Для отмены выполнения необходимо вызвать clearInterval / clearTimeout со значением, которое возвращают методы setInterval/setTimeout.

Вложенный setTimeout – более гибкий метод, чем setInterval. С его помощью последующий вызов может быть задан по-разному в зависимости от результатов предыдущего. Вложенный setTimeout позволяет задать задержку между выполнениями более точно, чем setInterval. Планирование с нулевой задержкой setTimeout(func,0) или, что то же самое, setTimeout(func) используется для вызовов, которые должны быть исполнены как можно скорее, после завершения исполнения текущего кода.
Браузер ограничивает 4-мя мс минимальную задержку между пятью и более вложенными вызовами setTimeout, а также для setInterval, начиная с 5-го вызова.

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

  • Перегружен процессор.
  • Вкладка браузера в фоновом режиме.
  • Работа ноутбука от аккумулятора.

Всё это может увеличивать минимальный интервал срабатывания таймера (и минимальную задержку) до 300 или даже 1000 мс в зависимости от браузера и настроек производительности ОС.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
33
Q

Агрегация данных

A

Data aggregation

Агрегация используется со строками и числами и относится к динамической генерации строк.
repeat ('icecream', 3); // icecreamicecreamicecream

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
34
Q

Аксессоры (геттеры и сеттеры)

A

Accessor properties

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

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

const person = { firstName: 'John', lastName: 'Doe', // Геттер для получения полного имени get fullName() { return this.firstName + ' ' + this.lastName; }, // Сеттер для установки полного имени set fullName(value) { const [firstName, lastName] = value.split(' '); this.firstName = firstName; this.lastName = lastName; } }; console.log(person.fullName); // "John Doe" person.fullName = 'Jane Smith'; console.log(person.firstName); // "Jane" console.log(person.lastName); // "Smith"

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
35
Q

Бесконечный цикл

A

Infinite loop (endless loop)

Бесконечный цикл - это конструкция в программировании, которая выполняется бесконечно, без завершения. Такой цикл не содержит условия или логики, которая могла бы привести к его завершению.

Бесконечные циклы обычно являются ошибкой программирования и приводят к “зависанию” программы, потреблению ресурсов процессора и памяти, и, как следствие, к зависанию или падению программы.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
36
Q

В каких случаях используются анонимные функции?

A

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
37
Q

В чем разница между Array.prototype.forEach и Array.prototype.map?

A

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

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
38
Q

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

A

Функции в JavaScript никак не привязаны к своему контексту this, с одной стороны, здорово – это позволяет быть максимально гибкими, одалживать методы и так далее.

Но с другой стороны – в некоторых случаях контекст может быть потерян. Способы явно указать this - методы bind, call и apply.

call - вызывает функцию с заданным this значением и аргументами, предоставленными один за другим через запятую.
Синтаксис метода call: func.call(context, arg1, arg2, …)

При этом вызывается функция func, первый аргумент call становится её this, а остальные передаются «как есть». Вызов func.call(context, a, b…) – то же, что обычный вызов func(a, b…), но с явно указанным this(=context).

const employee1 = { firstName: "John", lastName: "Rodson" }; const employee2 = { firstName: "Jimmy", lastName: "Baily" }; function invite(greeting1, greeting2) { console.log( greeting1 + " " + this.firstName + " " + this.lastName + ", " + greeting2 ); } invite("Hello", "How are you?"); // Hello undefined undefined, How are you? invite.call(employee1, "Hello", "How are you?"); // Hello John Rodson, How are you? invite.call(employee2, "Hello", "How are you?"); // Hello Jimmy Baily, How are you?

apply - вызов функции с переменным количеством аргументов в виде массива и с подменой контекста.
Если нам неизвестно, с каким количеством аргументов понадобится вызвать функцию, можно использовать более мощный метод: apply. Вызов функции при помощи func.apply работает аналогично func.call, но принимает массив аргументов вместо списка.

func.call(context, arg1, arg2) идентичен вызову func.apply(context, [arg1, arg2]);

function testForApply() { console.log(this); for (let i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } testForApply(1, 2, 3); // [object Window], 1, 2, 3 testForApply.apply("abc", [1, 2, 3, 4]); // abc, 1, 2, 3, 4

bind - создаёт “обёртку” над функцией, которая подменяет контекст этой функции. Поведение похоже на call и apply, но, в отличие от них, bind не вызывает функцию, а лишь возвращает “обёртку”, которую можно вызвать позже.
Синтаксис встроенного bind: var wrapper = func.bind(context, [arg1, arg2…])

Методы bind и call/apply близки по синтаксису, но есть важнейшее отличие. Методы call/apply вызывают функцию с заданным контекстом и аргументами. А bind не вызывает функцию. Он только возвращает «обёртку», которую мы можем вызвать позже, и которая передаст вызов в исходную функцию, с привязанным контекстом.

function testForBind() { console.log(this); } let wrapped = testForBind.bind("abc"); testForBind(); // [object Window] wrapped(); // abc

Также bind умеет подменять не только контекст, но и аргументы функции, осуществляя каррирование:

function add(a, b) { return a + b; } var addOne = add.bind(null, 1); alert(add(1, 2)); // 3 alert(addOne(2)); // 3

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
39
Q

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

A

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

Важно, при ===:
NaN ничему не равен, в том числе и NaN.
Положительные и отрицательные нули равны друг другу.
Два объекта строго равны, если они ссылаются на один и тот же объект.
Типы Null и Undefined не равны ===, но равны ==. т. е. null===undefined → false, но null==undefined → true

Интересно: Есть еще Object.is (новшество из ECMAScript 6). Object.is ведёт себя так же, как и тройное равно, но со специальной обработкой для NaN, -0 и +0, возвращая false при сравнении -0 и +0, и true для операции Object.is(NaN, NaN). (В то время как двойное или тройное равенство вернут false согласно стандарту IEEE 754.)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
40
Q

В чем разница между методами event.preventDefault() и event.stopPropagation()?

A

Метод event.preventDefault() отключает поведение элемента по умолчанию. Если использовать этот метод в элементе form, то он предотвратит отправку формы (submit). Если использовать его в contextmenu, то контекстное меню будет отключено (данный метод часто используется в keydown для переопределения клавиатуры, например, при создании музыкального/видео плеера или текстового редактора — прим. пер.). Чтобы узнать применен ли к элементу event.preventDefault() можно использовать event.defaulPrevented, возвращающее логическое значение, служащее индикатором применения к элементу метода event.preventDefault.

Метод event.stopPropagation() отключает распространение события (его всплытие или погружение).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
41
Q

Виртуальный метод (виртуальная функция)

A

Virtual function

Виртуальный метод (виртуальная функция) — в объектно-ориентированном программировании метод (функция) класса, который может быть переопределён в классах-наследниках так, что конкретная реализация метода для вызова будет определяться во время исполнения. Таким образом, программисту необязательно знать точный тип объекта для работы с ним через виртуальные методы: достаточно лишь знать, что объект принадлежит классу или наследнику класса, в котором объявлен метод. Одним из переводов слова virtual с английского языка может быть «фактический», что больше подходит по смыслу.

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

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
42
Q

Вложенные функции

A

Nested functions

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

function sayHiBye(firstName, lastName) { // helper nested function to use below function getFullName() { return firstName + " " + lastName; } alert( "Hello, " + getFullName() ); alert( "Bye, " + getFullName() ); }

Здесь вложенная функция getFullName() сделана для удобства. Он может обращаться к внешним переменным и поэтому может возвращать полное имя. Вложенные функции довольно распространены в JavaScript.
Что гораздо интереснее, вложенную функцию можно вернуть: либо как свойство нового объекта, либо как результат сам по себе. Затем его можно использовать в другом месте. Независимо от того, где, он по-прежнему имеет доступ к одним и тем же внешним переменным.

function makeCounter() { let count = 0; return function() { return count++; }; } let counter = makeCounter(); alert( counter() ); // 0 alert( counter() ); // 1 alert( counter() ); // 2

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
43
Q

Внутреннее и внешнее лексическое окружение

A

Внутреннее и внешнее лексическое окружение (или “scope”) являются важными концепциями в JavaScript, определяющими доступность переменных и функций во время выполнения кода.

Внутреннее лексическое окружение (Inner Lexical Environment) - это область видимости, в которой происходит определение и доступ к переменным и функциям внутри функции. Каждый раз, когда вызывается функция, создается новое внутреннее лексическое окружение для этой функции.

Пример внутреннего лексического окружения:

function greeting() { const message = 'Hello'; console.log(message); } greeting(); // Выводит "Hello"

В примере выше, внутреннее лексическое окружение функции greeting содержит переменную message, которая объявлена внутри функции и доступна только в этой функции.

Внешнее лексическое окружение (Outer Lexical Environment) - это область видимости, которая окружает текущее внутреннее лексическое окружение. Внешнее окружение предоставляет доступ к переменным и функциям, объявленным вне текущего внутреннего окружения.

Пример внешнего лексического окружения:

const count = 10; function increment() { console.log(count); } increment(); // Выводит 10, так как функция имеет доступ к переменной count из внешнего лексического окружения

В примере выше, функция increment имеет доступ к переменной count, которая объявлена во внешнем лексическом окружении.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
44
Q

Всплытие и погружение (перехват) событий DOM

A

Распространение события - Event Propagation
Когда какое-либо событие происходит в элементе DOM, оно на самом деле происходит не только в нем. Событие «распространяется» от объекта Window до вызвавшего его элемента (event.target). При этом событие последовательно пронизывает (затрагивает) всех предков целевого элемента. Распространение события имеет три стадии или фазы:
- фаза погружения (capturing phase) – событие сначала идёт сверху вниз;
- фаза цели (target phase) – событие достигло целевого(исходного) элемента;
- фаза всплытия (bubbling stage) – событие начинает всплывать.

При наступлении события, элемент, на котором оно произошло, помечается как «целевой» (event.target). Затем событие сначала двигается сверху вниз от корня документа (document) к целевому элементу, на каждом уровне (дочернем элементе) вызывая обработчики, назначенные через addEventListener(type, listener, true), где true – это сокращение для {capture: true}. При достижении целевого элемента, обработчики вызываются на самом целевом элементе (event.target). Затем событие начинает “всплывать”, т.е. двигается от целевого элемента вверх к корню документа, по пути вызывая обработчики, назначенные с префиксом on (например, onclick) или через addEventListener(type, listener, false) (или без третьего аргумента).

Каждый обработчик имеет доступ к свойствам события event:
- event.target – самый глубокий элемент, на котором произошло событие.
- event.currentTarget (== this) – элемент, на котором в данный момент сработал обработчик (тот, которому назначен конкретный обработчик).
- event.eventPhase – фаза, на которой сработал обработчик (1 - погружение, 2 - цели, 3 - всплытие).

Любой обработчик может остановить событие вызовом методов:
- event.stopPropagation() - препятствует дальнейшему всплытию события дальше по цепочке элементов.
- event.stopImmediatePropagation() - не только предотвращает всплытие, но и останавливает обработку событий на текущем элементе.

Всплытие событий DOM - это процесс последовательного срабатывания обработчиков события вверх по цепочке “родителей”, начиная с объекта DOM, инициировавшего событие, до объекта document.
Пример (learn.javascript.ru):
Например, есть 3 вложенных элемента FORM > DIV > P с обработчиком на каждом:
`<form onclick="alert('form')">FORM

<div>DIV
<p>P</p>
</div>

</form>

`
Клик по внутреннему <p> вызовет обработчик onclick:
- сначала на самом <p>;
- потом на внешнем <div>;
- затем на внешнем <form>, и т.д. вверх по цепочке до самого document.
Поэтому если кликнуть на <p>, то мы увидим три оповещения: p → div → form (события «всплывают» от внутреннего элемента вверх через родителей подобно тому, как всплывает пузырёк воздуха в воде).
Элемент, который вызывает событие, называется **целевым элементом**, и он доступен через свойство `event.target`.

Отличие event.target от this:
event.target – это элемент, на котором произошло событие, в процессе всплытия он не меняется;
this – это текущий элемент, до которого дошло всплытие, на нём сейчас выполняется обработчик.

Всплывают большинство событий, но есть исключения, например, событие focus не всплывает.

Прерывание всплытия
Событие “всплывает”, начиная с «целевого» элемента, вверх по цепочке родительских элементов до элемента <html>, а затем до объекта document (а иногда и до window).
Для прерывания всплытия любым промежуточным обработчиком используется метод event.stopPropagation(), например:
<body onclick="alert(сюда всплытие не дойдёт)"> <button onclick="event.stopPropagation()">Кликни меня</button> </body>

Метод event.stopPropagation() препятствует всплытию события дальше по цепочке элементов, однако если у элемента, на котором вызывается event.stopPropagation(), есть несколько обработчиков на одно событие, то все они будут выполнены.

Метод event.stopImmediatePropagation() не только предотвращает всплытие, но и останавливает обработку событий на текущем элементе.
Не рекомендуется прекращать всплытие без необходимости.

Погружение (перехват) событий
Обработчики, добавленные через свойство DOM-объекта, или через HTML-атрибуты, или через addEventListener(event, handler) с двумя аргументами работают только на фазах цели (target phase) и всплытия (bubbling stage).
Чтобы поймать событие на стадии погружения, нужно использовать аргумент capture метода addEventListener(event, handler):
- если аргумент false (по умолчанию), то событие будет поймано при всплытии;
- если аргумент true, то событие будет перехвачено при погружении.

elem.addEventListener(..., {capture: true}) // или просто "true", как сокращение для {capture: true} elem.addEventListener(..., true)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
45
Q

Как выровнять (сгладить) вложенный массив

A

Использование Array.prototype.concat()
Это можно сделать рекурсивно с помощью reduce() метод с concat() метод. В следующем примере показано, как рекурсивно сгладить массив с помощью reduce а также concat метод.

function flatten(arr) { return arr.reduce((acc, cur) => acc.concat(Array.isArray(cur) ? flatten(cur) : cur), []); }; const arr = [[1,2],[3,[4,[5]]]]; const flattened = flatten(arr); console.log(flattened); // результат: [ 1, 2, 3, 4, 5 ]

Использование Array.prototype.flat()
ECMA 2019 представила новый метод под названием flat() для рекурсивного выравнивания массива. В качестве параметра принимает глубину вложенного массива, т.е. 1 по умолчанию. Чтобы сгладить любую глубину вложенного массива, используйте Infinity с flat() метод.

const arr = [[1,2],[3,[4,[5]]]]; const flattened = arr.flat(Infinity); console.log(flattened); // результат: [ 1, 2, 3, 4, 5 ]

Использование функции генератора
В качестве альтернативы вы можете написать функцию-генератор для глубокого выравнивания массива любой глубины. В следующем примере кода показано, как реализовать это с помощью Array.isArray() метод.

function* flatten(arr) { for (const val of arr) { Array.isArray(val) ? yield* flatten(val) : yield val; } } const arr = [[1,2],[3,[4,[5]]]]; const flattened = [...flatten(arr)]; console.log(flattened); // результат: [ 1, 2, 3, 4, 5 ]

Использование библиотеки подчеркивания
Библиотека Underscore JavaScript предлагает _.flatten метод, который может сгладить вложенный массив любой глубины.

const _ = require('underscore'); const arr = [[1,2], [3,[4,5]]]; const flattened = _.flatten(arr); console.log(flattened); результат: [ 1, 2, 3, 4, 5 ]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
46
Q

Разница между выражением и инструкцией

A

Выражение (англ. expression) — это код, который после выполнения возвращает какое-либо значение. Например, 5 + 3 вернёт 8, а Math.random() — случайное число. Выражения оперируют с данными — это могут быть не только числа, но и строки, и сложные структуры данных. Данные сочетаются с операциями над ними (например, сложение, вычитание, умножение), и программа выдаёт результат выражения. Удобно представлять выражение как наборы данных в сочетании с операциями, которые их обрабатывают.

Инструкция (англ. statement) — это отдельная команда в коде, которая выполняет определённое действие. Инструкции ничего не вычисляют и не возвращают результат, поэтому они не являются выражениями. Например, if позволяет создать ветвление в программе, for позволяет повторять одно и то же действие.
- управление потоком выполнения (if и else, switch, throw и так далее);
- итерации (for, while и так далее);
- объявление значений (var, let, const);
- функции (function, return и так далее);
- прочие (debugger, import, export).

Исключение: в JavaScript есть выражение, которое позволяет возвращать значение по условию. Таким выражением является тернарный оператор. Как любое выражение, он возвращает значение.
const result = someNumber > 10 ? 'Больше десяти' : 'Меньше десяти'

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
47
Q

Вычисляемые свойства объекта

A

Object computed props

Мы можем использовать квадратные скобки в литеральной нотации для создания вычисляемого свойства.
Пример:
let fruit = prompt("Какой фрукт купить?", "apple"); let bag = { [fruit]: 5, // имя свойства будет взято из переменной fruit }; alert( bag.apple ); // 5, если fruit="apple"

Смысл вычисляемого свойства прост: запись [fruit] означает, что имя свойства необходимо взять из переменной fruit.
И если посетитель введёт слово “apple”, то в объекте bag теперь будет лежать свойство {apple: 5}.
По сути, пример выше работает так же, как и следующий пример:
let fruit = prompt("Какой фрукт купить?", "apple"); let bag = {}; // имя свойства будет взято из переменной fruit bag[fruit] = 5;

…Но первый пример выглядит лаконичнее.
Мы можем использовать и более сложные выражения в квадратных скобках:
let fruit = 'apple'; let bag = { [fruit + 'Computers']: 5 // bag.appleComputers = 5 };

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

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
48
Q

Граф (Структуры данных)

A

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

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

Основные методы:
addVertex – добавление новой вершины;
addEdge – добавление нового ребра.

class Graph { dfs(startVertex, callback) { let list = this.vertices; // список смежности let stack = [startVertex]; // стек вершин для перебора let visited = { [startVertex]: 1 }; // посещенные вершины // function handleVertex(vertex) { // вызываем коллбэк для посещенной вершины callback(vertex); // // получаем список смежных вершин let reversedNeighboursList = [...list[vertex]].reverse(); // reversedNeighboursList.forEach(neighbour => { if (!visited[neighbour]) { // отмечаем вершину как посещенную visited[neighbour] = 1; // добавляем в стек stack.push(neighbour); } }); } // // перебираем вершины из стека, пока он не опустеет while(stack.length) { let activeVertex = stack.pop(); handleVertex(activeVertex); } // // проверка на изолированные фрагменты stack = Object.keys(this.vertices); // while(stack.length) { let activeVertex = stack.pop(); if (!visited[activeVertex]) { visited[activeVertex] = 1; handleVertex(activeVertex); } } } }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
49
Q

Двоичное дерево (Структуры данных)

A

Binary Tree
Двоичное дерево — структура данных, в которой каждый узел имеет максимум два дочерних элемента. Дочерние элементы бывают левым и правым. Ключ левого дочернего узла меньше, чем у родительского. Ключ правого дочернего узла больше, чем у родительского.
Оптимальны для сортировки и поиска.
Эффективность («О» большое):
Индексирование: O(log n).
Поиск: O(log n).
Вставка: O(log n).

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

Основные операции:
Добавление нового узла (add);
Удаление узла по его значению (remove);
Поиск узла по значению (find);
Обход всех элементов (traverse).
findMin: получить минимальный узел
findMax: получить максимальный узел
isPresent: проверить наличие определенного узла

Бинарное дерево поиска:
class Node { constructor(data, left = null, right = null) { this.data = data this.left = left this.right = right } } // class BST { constructor() { this.root = null } // add(data) { const node = this.root if (node === null) { this.root = new Node(data) return } else { const searchTree = function(node) { if (data < node.data) { if (node.left === null) { node.left = new Node(data) return } else if (node.left !== null) { return searchTree(node.left) } } else if (data > node.data) { if (node.right === null) { node.right = new Node(data) return } else if (node.right !== null) { return searchTree(node.right) } } else { return null } } return searchTree(node) } } // findMin() { let current = this.root while (current.left !== null) { current = current.left } return current.data } // findMax() { let current = this.root while (current.right !== null) { current = current.right } return current.data } // find(data) { let current = this.root while (current.data !== data) { if (data < current.data) { current = current.left } else { current = current.right } if (current === null) { return null } } return current } // isPresent(data) { let current = this.root while (current) { if (data === current.data) { return true } data < current.data ? current = current.left : current = current.right } return false } // remove(data) { const removeNode = function(node, data) { if (node === null) return null if (data === node.data) { // потомки отсутствуют if (node.left === null && node.right === null) return null // отсутствует левый узел if (node.left === null) return node.right // отсутствует правый узел if (node.right === null) return node.left // имеется два узла let tempNode = node.right while (tempNode.left !== null) { tempNode = tempNode.left } node.data = tempNode.data node.right = removeNode(node.right, tempNode.data) return node } else if (data < node.data) { node.left = removeNode(node.right, data) return node } else { node.right = removeNode(node.right, data) return node } } this.root = removeNode(this.root, data) } }

Интересно: Кроме двоичных, широкое практическое применение имеют деревья с четырьмя узлами (дерево квадрантов). Они используются в геймдеве для организации сетки. Каждый узел в таком дереве представляет одно направление (север-запад, юго-восток и так далее).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
50
Q

Делегирование событий

A

В случае, когда нам нужно обработать событие на нескольких элементах, имеющих общего предка мы «вешаем» слушатель не на элементы, а на предка. После, с помощью event.target, мы можем получить конкретный элемент, на котором было совершено целевое событие и обработать его.

Всплытие и перехват событий позволяет реализовать один из самых важных приёмов разработки – делегирование.
Идея в том, что если у нас есть много элементов, события на которых нужно обрабатывать похожим образом, то вместо того, чтобы назначать обработчик каждому, мы ставим один обработчик на их общего предка. Из него можно получить целевой элемент event.target, понять на каком именно потомке произошло событие и обработать его.

К примеру есть табличка и наша задача – реализовать подсветку ячейки <td> при клике.
Вместо того, чтобы назначать обработчик onclick для каждой ячейки <td> (их может быть очень много) – мы повесим «единый» обработчик на элемент <table>. Он будет использовать event.target, чтобы получить элемент, на котором произошло событие, и подсветить его.

Например, нам нужно сделать меню с разными кнопками: «Сохранить (save)», «Загрузить (load)», «Поиск (search)» и т.д. И есть объект с соответствующими методами save, load, search… Как их состыковать?
Первое, что может прийти в голову – это найти каждую кнопку и назначить ей свой обработчик среди методов объекта. Но существует более элегантное решение. Мы можем добавить один обработчик для всего меню и атрибуты data-action для каждой кнопки в соответствии с методами, которые они вызывают:
<button data-action="save">Нажмите, чтобы Сохранить</button> Обработчик считывает содержимое атрибута и выполняет метод. onClick(event) { let action = event.target.dataset.action; if (action) { this[action](); } }

Зачем использовать:
Упрощает процесс инициализации и экономит память: не нужно вешать много обработчиков.
Меньше кода: при добавлении и удалении элементов не нужно ставить или снимать обработчики.
Удобство изменений DOM: можно массово добавлять или удалять элементы путём изменения innerHTML и ему подобных.
Конечно, у делегирования событий есть свои ограничения:
Во-первых, событие должно всплывать. Некоторые события этого не делают. Также, низкоуровневые обработчики не должны вызывать event.stopPropagation().
Во-вторых, делегирование создаёт дополнительную нагрузку на браузер, ведь обработчик запускается, когда событие происходит в любом месте контейнера, не обязательно на элементах, которые нам интересны. Но обычно эта нагрузка настолько пустяковая, что её даже не стоит принимать во внимание.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
51
Q

Деструктурирующее присваивание

A

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

Полный синтаксис для объекта:

let {prop : varName = default, ...rest} = object

Cвойство prop объекта object здесь должно быть присвоено переменной varName. Если в объекте отсутствует такое свойство, переменной varName присваивается значение по умолчанию.
Свойства, которые не были упомянуты, копируются в объект rest.

Полный синтаксис для массива:

let [item1 = default, item2, ...rest] = array

Первый элемент отправляется в item1; второй отправляется в item2, все остальные элементы попадают в массив rest.
Можно извлекать данные из вложенных объектов и массивов, для этого левая сторона должна иметь ту же структуру, что и правая.

Нежелательные элементы массива также могут быть отброшены с помощью дополнительной запятой:

// второй элемент не нужен let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; alert( title ); // Consul

Работает с любым перебираемым объектом с правой стороны
…На самом деле мы можем использовать любой перебираемый объект, не только массивы:

let [a, b, c] = "abc"; let [one, two, three] = new Set([1, 2, 3]);

Присваивайте чему угодно с левой стороны
Мы можем использовать что угодно «присваивающее» с левой стороны.
Например, можно присвоить свойству объекта:

let user = {}; [user.name, user.surname] = "Ilya Kantor".split(' '); alert(user.name); // Ilya alert(user.surname); // Kantor

Цикл с .entries()
В предыдущей главе мы видели метод Object.entries(obj).
Мы можем использовать его с деструктуризацией для цикличного перебора ключей и значений объекта:

let user = { name: "John", age: 30 }; // цикл по ключам и значениям for (let [key, value] of Object.entries(user)) { alert(${key}:${value}); // name:John, затем age:30 }

…то же самое для map:

let user = new Map(); user.set("name", "John"); user.set("age", "30"); // Map перебирает как пары [ключ, значение], что очень удобно для деструктурирования for (let [key, value] of user) { alert(${key}:${value}); // name:John, затем age:30 }

Трюк обмена переменных
Существует хорошо известный трюк для обмена значений двух переменных с использованием деструктурирующего присваивания:

let guest = "Jane"; let admin = "Pete"; // Давайте поменяем местами значения: сделаем guest = "Pete", а admin = "Jane" [guest, admin] = [admin, guest]; alert(${guest} ${admin}); // Pete Jane (успешно заменено!)

Здесь мы создаём временный массив из двух переменных и немедленно деструктурируем его в порядке замены.
Таким образом, мы можем поменять местами даже более двух переменных.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
52
Q

Динамические импорты

A

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

Пример использования динамического импорта:

// Загрузка модуля по требованию import('./module.js') .then(module => { // Использование экспорта модуля module.myFunction(); }) .catch(error => { // Обработка ошибок при загрузке модуля console.error('Ошибка загрузки модуля:', error); });

В примере выше мы используем синтаксис import() для динамической загрузки модуля из файла module.js. После успешной загрузки модуля, мы можем использовать его экспорты, например, вызвать myFunction().

Динамические импорты возвращают Promise, поэтому мы можем использовать .then() для обработки успешного завершения загрузки и .catch() для обработки ошибок.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
53
Q

Динамическое количество параметров функции

A

Многие встроенные функции JavaScript поддерживают произвольное количество аргументов.

Math.max(arg1, arg2, ..., argN) – вычисляет максимальное число из переданных.
Object.assign(dest, src1, ..., srcN) – копирует свойства из исходных объектов src1..N в целевой объект dest.

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

Остаточные параметры могут быть обозначены через три точки …. Буквально это значит: «собери оставшиеся параметры и положи их в массив».
function sumAll(...args) { // args — имя массива let sum = 0; for (let arg of args) sum += arg; return sum; }

Все аргументы функции находятся в псевдомассиве arguments под своими порядковыми номерами. Раньше в языке не было остаточных параметров, и получить все аргументы функции можно было только с помощью arguments. Хотя arguments похож на массив, и его тоже можно перебирать, это всё же не массив. Он не поддерживает методы массивов, поэтому мы не можем, например, вызвать arguments.map(...). Стрелочные функции не имеют “arguments”

Оператор расширения.
Он похож на остаточные параметры – тоже использует …, но делает совершенно противоположное. Когда …arr используется при вызове функции, он «расширяет» перебираемый объект arr в список аргументов.
let arr = [3, 5, 1]; alert( Math.max(...arr) ); // 5 (оператор "раскрывает" массив в список аргументов)

Мы также могли бы использовать Array.from(), но между Array.from(obj) и [...obj] есть разница:
- Array.from работает как с псевдомассивами, так и с итерируемыми объектами
- Оператор расширения работает только с итерируемыми объектами
Выходит, что если нужно сделать из чего угодно массив, то Array.from — более универсальный метод.

Если … располагается в конце списка параметров функции, то это «остаточные параметры». Он собирает остальные неуказанные аргументы и делает из них массив.
Если … встретился в вызове функции или где-либо ещё, то это «оператор расширения». Он извлекает элементы из массива.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
54
Q

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

A

Ключевое слово «new» используется в функциях-конструкторах для создания нового объекта (нового экземпляра класса или так называемого инстанса класса).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
55
Q

Для чего используется директива «use strict»?

A

«use strict» — это директива ES5, которая заставляет весь наш код или код отдельной функции выполняться в строгом режиме. Строгий режим вводит некоторые ограничения по написанию кода, тем самым позволяя избегать ошибок на ранних этапах.
1. Нельзя присваивать значения или обращаться к необъявленным переменным.
2. Запрещено присваивать значения глобальный переменным, доступным только для чтения или записи
3. Нельзя удалить «неудаляемое» свойство объекта
4. Запрещено дублирование параметров
5. Нельзя создавать функции с помощью функции eval
6. Значением «this» по умолчанию является undefined
и тд

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
56
Q

Доступ к внутренним (вложенным) элементам массива

A

Accessing nested array elements

Через array [index] [index]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
57
Q

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

A

Closure [‘klouzhe]

Замыкание — это способность функции в JS запомнить лексическое окружение в котором она была создана, т.е. хранить ссылку на это окружение. Другими словами, замыкание даёт вам доступ к области видимости(Scope) внешней функции из внутренней функции, даже если первая уже была прекращена. В JavaScript, почти все функции изначально являются замыканиями (кроме созданных через new Function, в её [[Environment]] записывается ссылка на глобальное окружение).

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

Объект лексического окружения состоит из двух частей:
- Environment Record – объект, в котором как свойства хранятся все локальные переменные (а также некоторая другая информация, такая как значение this).
- Ссылка на внешнее лексическое окружение – то есть то, которое соответствует коду снаружи

const x = 1;
const y = function (){
i = “hi”;
console.log(i)
}
y()

В данном примере глобальное лексическое окружение включает: 1. переменные x и y, 2. ссылку на Null, так как глобальному окружению не на что ссылаться. Локальное лексическое окружение (внутри функции) имеет 1. переменную i и 2. ссылку на ближайшее внешнее окружение: глобальное. Локальное лексическое окружение имеет доступ как к своим переменным, так и к переменным снаружи, так как у него есть ссылка на внешнее лексическое окружение. Важно, что локальное лексическое окружение будет создано только во время вызова функции y().

Когда код хочет получить доступ к переменной – сначала происходит поиск во внутреннем лексическом окружении, затем во внешнем, затем в следующем и так далее, до глобального.

function getCounter() {
let counter = 0;
return function() {
return counter++;
}}

let count = getCounter();

console.log(count()); // 0
console.log(count()); // 1
console.log(count()); // 2

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

  • контроля побочных эффектов;
  • создания приватных переменных.

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
58
Q

Изменение массива

A

Изменение элементов массива воможно по индексу
const animals = ['cats', 'dogs', 'birds'];
// Меняется первый элемент массива
animals[0] = 'horses';

Метод arr.splice(str) – это универсальный «швейцарский нож» для работы с массивами. Умеет всё: добавлять, удалять и заменять элементы.
arr.splice(1, 1); // начиная с позиции 1, удалить 1 элемент arr.splice(0, 3, "Давай", "танцевать"); // удалить 3 первых элемента и заменить их другими let removed = arr.splice(0, 2); // удалить 2 первых элемента

Добавление элемента в массив
Метод push() добавляет элемент в конец массива
Метод unshift() добавляет элемент в начало массива
По индексу
const animals = ['cats', 'dogs', 'birds']; animals[3] = 'horses';

Удаление элемента из массива
Удалить элемент из массива можно с помощью специальной конструкции delete: delete arr[index].

const animals = ['cats', 'dogs', 'birds']; delete animals[1]; // удаляем элемент под индексом 1 console.log(animals); // => [ 'cats', <1 empty item>, 'birds' ]

arr.pop() – извлекает элемент из конца
arr.shift() – извлекает элемент из начала

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
59
Q

Интерполяция строк

A

String interpolation

Интерполяция строк - способ соединения строк через вставку значений переменных в строку-шаблон с помощью фигурных скобок.
Hi, ${name}!

` - обратные апострофы или бэктики

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
60
Q

Итератор

A

Объекты, которые можно использовать в цикле for..of, называются итерируемыми. Технически итерируемые объекты должны иметь метод Symbol.iterator.
Результат вызова obj[Symbol.iterator] называется итератором. Он управляет процессом итерации.
Итератор должен иметь метод next(), который возвращает объект {done: Boolean, value: any}, где done:true сигнализирует об окончании процесса итерации, в противном случае value – следующее значение.
Метод Symbol.iterator автоматически вызывается циклом for..of, но можно вызвать его и напрямую.
Встроенные итерируемые объекты, такие как строки или массивы, также реализуют метод Symbol.iterator.
const rangeIterator = '012'[Symbol.iterator](); console.log(rangeIterator.next()); // {"value": "0", "done": false} console.log(rangeIterator.next()); // {"value": "1", "done": false} console.log(rangeIterator.next()); // {"value": "1", "done": false} console.log(rangeIterator.next()); // {"value": undefined, "done": true} // const person = { age: 40, name: "Kolya", [Symbol.iterator]: function*() { yield this.age; yield this.name; } }; // for (const value of person) { console.log(value); // 40 // Kolya }

Итератор — это объект, который умеет обращаться к элементам коллекции по одному за раз, при этом отслеживая своё текущее положение внутри этой последовательности.
В JavaScript итератор — это объект, который возвращает следующий элемент последовательности, через метод next(). Этот метод возвращает объект с двумя свойствами:
value — значение текущего элемента коллекции.
done — индикатор, указывающий, есть ли ещё в коллекции значения, доступные для перебора.

В некоторых случаях интерфейс итератора вызывается по умолчанию. Такие объекты как String, Array, Map и Set являются
итерируемыми, потому что их прототипы содержат Symbol.iterator.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
61
Q

Итерируемый (перебираемый) объект

A

Итерируемые или, иными словами, «перебираемые» объекты – это те, содержимое которых можно перебрать в цикле.

Symbol — это уникальный и иммутабельный идентификатор. Создается с помощью функции Symbol(), также может иметь метку Symbol(‘foo’). Символы с одинаковыми метками не равны друг другу, и вообще, любые символы не равны между собой (помним про уникальность). Существуют системные символы, такие как Symbol.iterator , Symbol.toPrimitive и другие. Системные символы используются самим языком, но мы также можем применять их, чтобы изменять дефолтное поведение некоторых объектов.
Symbol.iterator в основном используется языком в цикле for…of при переборе свойств объекта. Так же его можно использовать напрямую со встроенными типами данных. Список итерируемых типов в js: String, Array, TypedArray, Map, Set.

Для возможности использовать объект в for..of нужно создать в нём свойство с названием Symbol.iterator (системный символ).
При вызове метода Symbol.iterator перебираемый объект должен возвращать другой объект («итератор»), который умеет осуществлять перебор.
По стандарту у такого объекта должен быть метод next(), который при каждом вызове возвращает очередное значение и проверяет, окончен ли перебор.

const myObject = { values: [1, 2, 3], [Symbol.iterator]() { let index = 0; const values = this.values; // return { next() { if (index < values.length) { return { value: values[index++], done: false }; } // return { done: true }; } }; } }; // for (const value of myObject) { console.log(value); }

В этом примере мы создали объект myObject, у которого есть свойство с символом Symbol.iterator. Метод, связанный с символом, возвращает объект-итератор, который в свою очередь имеет метод next(). Метод next() отвечает за возврат очередного значения и проверку, закончен ли перебор. В цикле for..of мы проходим по объекту myObject, и на каждой итерации получаем значение и выводим его в консоль.

Symbol.iterator используется при деструктуризации:

const [a, b, c] = route; // a - "Москва" // b - "Питер" // с - "Казань"

и со spread оператором:

function test(a, b, c) { console.log(a, b, c) } test(…route) // "Москва" "Питер" "Казань"

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
62
Q

Как можно клонировать объект?

A
  • Можно использовать оператор остатка ….
  • Можно использовать Object.assign(newObj, oldObj).
    Но эти подходы не позволяют выполнить глубокое клонирование. Поэтому, если нам нужно клонировать объект со вложенными объектами, мы можем использовать
  • либо метод какой-либо библиотеки (lodash),
  • либо сделать это средствами встроенного объекта JSON.

JSON.parse(JSON.stringify(objectToClone))

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
63
Q

Как определить наличие свойства в объекте?

A
  1. Первый способ состоит в использовании оператора «in»:

console.log('prop' in o) // true console.log('prop1' in o) // false

  1. Второй — использовать метод hasOwnProperty:

console.log(o.hasOwnProperty('prop2')) // true console.log(o.hasOwnProperty('prop1')) // false

  1. Третий — индексная нотация массива:

console.log(o['prop']) // bwahahah console.log(o['prop1']) // undefined

Важно: Оператор «in» проверяет наличие свойства не только в самом объекте, но и в его прототипах, а метод hasOwnProperty — только в объекте.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
64
Q

Как проверить, является ли значение null?

A

typeof null == ‘object’ всегда будет возвращать true по историческим причинам. Для проверки, является ли значение null можно использовать оператор строгого равенства (===):

function isNull(value){ return value === null }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
65
Q

Как работает прототипное наследование?

A

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
66
Q

Как можно добавить элемент в конец массива?

A

Array.prototype.push()

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
67
Q

Как можно добавить элемент в начало массива?

A

Array.prototype.unshift()

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
68
Q

Какие конструкции языка вы используете для обхода массивов и объектов?

A

В случае с массивами, это чаще всего forEach и map. Реже возникает необходимость в for, for in, for of, reduce, filter и подобных.
Метод «arr.forEach(callback[, thisArg])» используется для перебора массива.
Он для каждого элемента массива вызывает функцию callback.
Этой функции он передаёт три параметра callback(item, i, arr):
item – очередной элемент массива.
i – его номер.
arr – массив, который перебирается.
Метод «arr.filter(callback[, thisArg])» используется для фильтрации массива через функцию.
Он создаёт новый массив, в который войдут только те элементы arr, для которых вызов callback(item, i, arr) возвратит true.

Метод «arr.map(callback[, thisArg])» используется для трансформации массива.
Он создаёт новый массив, который будет состоять из результатов вызова callback(item, i, arr) для каждого элемента arr.

Эти методы используются для проверки массива.
Метод «arr.every(callback[, thisArg])» возвращает true, если вызов callback вернёт true для каждого элемента arr.
Метод «arr.some(callback[, thisArg])» возвращает true, если вызов callback вернёт true для какого-нибудь элемента arr.
Метод «arr.reduce(callback[, initialValue])» используется для последовательной обработки каждого элемента массива с сохранением промежуточного результата.

А чтобы обойти объект, понадобится немного изобретательности. Один из вариантов - получить ключи с помощью Object.keys, по которым впоследствии пройти с помощью forEach. Либо же можно воспользоваться Object.values, Object.entries, Object.keys.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
69
Q

Какие приемы работы с асинхронным кодом в JS Вы знаете?

A

Функции обратного вызова (Callbacks).
Промисы (Promises).
Async/await.
Библиотеки вроде async.js, blueprint, q, co.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
70
Q

Что такое контекст? Какое значение имеет this?

A

В JavaScript, контекст (this) представляет текущий объект, на котором выполняется код во время выполнения функции. Контекст this в JavaScript создается во время выполнения функции и зависит от контекста вызова функции.
Проще говоря this - это ссылка на объект, который вызывает функцию в данный момент.

Контекст (this) в JavaScript может быть определен следующими способами:

  1. Глобальный контекст: В глобальной области видимости контекст (this) ссылается на глобальный объект, такой как window в браузере или global в Node.js.

function getThis() {
console.log(‘this’);
}

getThis() // window

  1. Функциональный контекст: Когда функция вызывается как метод объекта, контекст (this) ссылается на сам этот объект.

const obj = {
name: ‘John’,
greet: function() {
console.log(‘Hello, ‘ + this.name);
}
}

obj.greet(); // Выведет ‘Hello, John’

  1. Контекст при использовании call, apply или bind: Методы call, apply и bind позволяют явно определить контекст (this) при вызове функции.

function sayHello() {
console.log(‘Hello, ‘ + this.name);
}

const person = {
name: ‘Mary’
};

sayHello.call(person); // Выведет ‘Hello, Mary’

  1. Контекст в стрелочных функциях: Стрелочные функции имеют лексический контекст, что означает, что контекст (this) внутри стрелочной функции берется из окружающего контекста. Например:

const obj = {
name: ‘Alice’,
greet: function() {
const innerFn = () => {
console.log(‘Hello, ‘ + this.name);
}
innerFn();
}
}

obj.greet(); // Выведет ‘Hello, Alice’

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
71
Q

Каррирование

A

Каррирование (Currying) - это техника в функциональном программировании, которая позволяет превращать функцию с несколькими аргументами в последовательность функций с одним аргументом. Это позволяет нам создавать новые функции на основе существующих, фиксируя некоторые из аргументов заранее.

В JavaScript каррирование можно реализовать с использованием замыканий. При вызове функции с некоторыми аргументами, она возвращает новую функцию, которая ожидает оставшиеся аргументы и выполняет нужные операции. Каррирование позволяет легко получать частичные функции. Как мы видели в примерах с логами: универсальная функция log(date, importance, message) после каррирования возвращает нам частично применённую функцию, когда вызывается с одним аргументом, как log(date) или двумя аргументами, как log(date, importance).

Пример каррирования в JavaScript:

function multiply(a) { return function(b) { return a * b; }; } // const multiplyByTwo = multiply(2); // Функция, которая умножает число на 2 console.log(multiplyByTwo(4)); // Выводит: 8

В этом примере функция multiply принимает один аргумент a и возвращает новую функцию, которая принимает аргумент b. Во время вызова multiplyByTwo(4), значение a равно 2, и мы передаем аргумент b = 4. Результатом будет произведение числа 2 на 4, то есть 8.

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
72
Q

Кастомные события

A

Можно не только назначать обработчики, но и генерировать события из JavaScript-кода. События DOM предоставляют большую функциональность. В некоторых случаях может потребоваться создать пользовательское событие для более общего использования.
Чтобы создать пользовательское событие, вы используете Пользовательское событие CustomEvent.

var myEvent; var customEvent = function () { try { myEvent = new CustomEvent( "anAction", { detail: { description: "a description of the event", timeofevent: new Date(), eventcode: 2 }, bubbles: true, cancelable: true } ); document.addEventListener("anAction", customEventHandler); //Finally, the event is raised by using the dispatchEvent method: document.dispatchEvent(myEvent); } catch (e) { alert(e.message); } } //A function called customEventHandler must exist for all this to work: function customEventHandler() { alert(window.event.detail.description); }

Конструктор объекта CustomEvent принимает два параметра:
Первый параметр — это имя события . Это все, что имеет смысл для того, что событие должно представлять. В этом примере событие называется anAction.
Второй параметр — это динамический объект , который содержит свойство детали, которому могут быть назначены свойства, содержащие информацию, которая должна быть передана обработчику событий.
Кроме того, параметр предоставляет возможность указать, должно ли событие всплывать и может ли событие быть отменено.
Затем событие назначается элементу на странице с помощью метода addEventListener , а событие вызывается с помощью метода dispatchEvent

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
73
Q

Коммутативное значение

A

Commutative property

Коммутативность - свойство операции, когда изменение порядка операндов не влияет на результат.
5 * 2 === 2 * 5
3 + 4 === 4 + 3

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
74
Q

Конкатенация строк

A

String concatenation

Объединение строк через оператор +

let first = "hello"; let second = "world"; let concat = first + second; // "hello world"

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
75
Q

Конструкция “switch”

A

Конструкция switch заменяет собой сразу несколько if. Она представляет собой более наглядный способ сравнить выражение сразу с несколькими вариантами.

let a = 2 + 2; switch (a) { case 3: alert( 'Маловато' ); break; case 4: alert( 'В точку!' ); break; case 5: alert( 'Перебор' ); break; default: alert( "Нет таких значений" ); }

Если break нет, то выполнение пойдёт ниже по следующим case, при этом остальные проверки игнорируются.
Любое выражение может быть аргументом для switch/case
Несколько вариантов case, использующих один код, можно группировать.

case 3: // группируем оба case case 5: alert('Неправильно!'); alert("Может вам посетить урок математики?"); break;

Нужно отметить, что проверка на равенство всегда строгая. Значения должны быть одного типа, чтобы выполнялось равенство.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
76
Q

Контекст выполнения

A

Контекст выполнения в JavaScript (Execution Context) - это внутренняя структура данных, которая содержит информацию о текущем состоянии выполнения кода во время работы программы. Каждый раз, когда JavaScript-код запускается, создается новый контекст выполнения, который содержит переменные, функции и другие данные, необходимые для выполнения кода. Так как Javascript является однопоточным (single-threaded), в любой момент времени может быть запущен только один контекст выполнения.

// глобальный контекст выполнения function printMyName () { // новый контекст выполнения return Alex; } // function sayMyName () { // новый контекст выполнения return printMyName(); } // sayMyName(); // // глобальный контекст выполнения

Контекст выполнения состоит из трех основных компонентов:

  1. Global Execution Context (глобальный контекст выполнения) - создается при загрузке скрипта и представляет собой начальный контекст выполнения. В нем определены все глобальные переменные, функции и другие данные, доступные на уровне всего скрипта.
  2. Function Execution Context (контекст выполнения функции) - создается каждый раз при вызове функции. Он содержит локальные переменные и параметры функции, а также ссылку на контекст выполнения, из которого она была вызвана (внешний контекст выполнения).
  3. Eval Function Execution Context (контекст выполнения функции eval) - создается внутри функции eval(). Он работает подобно контексту выполнения функции, но используется для выполнения кода, переданного в функцию eval().

Стек выполнения (execution stack), который ещё называют стеком вызовов (call stack), это LIFO-стек, который используется для хранения контекстов выполнения, создаваемых в ходе работы кода.

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

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
77
Q

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

A

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

В JavaScript есть два типа областей видимости:

  1. Глобальная область видимости (Global Scope) - переменные и функции, объявленные вне всех функций, имеют глобальную область видимости. Они могут быть доступны из любого места кода. Пример:

const globalVar = 'Global Variable'; function globalFunction() { console.log(globalVar); // Выводит 'Global Variable' } globalFunction();

В данном примере переменная globalVar объявлена в глобальной области видимости и доступна из функции globalFunction.

  1. Локальная область видимости (Local Scope) - переменные и функции, объявленные внутри функций, имеют локальную область видимости. Они видны только внутри функции, где были объявлены. Пример:

function localFunction() { const localVar = 'Local Variable'; console.log(localVar); // Выводит 'Local Variable' } localFunction(); console.log(localVar); // Ошибка: localVar is not defined

В данном примере переменная localVar объявлена внутри функции localFunction и доступна только внутри этой функции. Попытка обратиться к ней за пределами функции вызовет ошибку.

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
78
Q

Как копировать часть массива

A

Метод slice() позволяет скопировать часть массива. Для этого он принимает два параметра:

slice(начальный_индекс, конечный_индекс)
Первый параметр указывает на начальный индекс элемента, с которого которые используются для выборки значений из массива. А второй параметр - конечный индекс, по который надо выполнить копирование.

Например, выберем в новый массив элементы, начиная с 1 индекса по индекс 4 не включая:

const users = [“Tom”, “Sam”, “Bill”, “Alice”, “Kate”];
const people = users.slice(1, 4);
console.log(people); // [“Sam”, “Bill”, “Alice”]
И поскольку индексация массивов начинается с нуля, то в новом массиве окажутся второй, третий и четвертый элемент.

Если указан только начальный индекс, то копирование выполняется до конца массива

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
79
Q

Куча (Структуры данных)

A

Heap
Куча – это самобалансирующаяся структура, при каждой операции она сортирует себя, чтобы все уровни (кроме последнего) были заполнены. Похожа на деревья: у них также есть корневые и дочерние узлы, но отличается иерархия. Бывает max-heap - где корень всегда является максимальным элементом и min-heap, где корень является минимальным элементом. Кучи используют для сортировки объектов или реализации очередей с приоритетом.

class MinHeap { // constructor () { /* Initialing the array heap and adding a dummy element at index 0 */ this.heap = [null] } // getMin () { /* Accessing the min element at index 1 in the heap array */ return this.heap[1] } // insert (node) { // /* Inserting the new node at the end of the heap array */ this.heap.push(node) // /* Finding the correct position for the new node */ // if (this.heap.length > 1) { let current = this.heap.length - 1 // /* Traversing up the parent node until the current node (current) is greater than the parent (current/2)*/ while (current > 1 && this.heap[Math.floor(current/2)] > this.heap[current]) { // /* Swapping the two nodes by using the ES6 destructuring syntax*/ [this.heap[Math.floor(current/2)], this.heap[current]] = [this.heap[current], this.heap[Math.floor(current/2)]] current = Math.floor(current/2) } } } // remove() { /* Smallest element is at the index 1 in the heap array */ let smallest = this.heap[1] // /* When there are more than two elements in the array, we put the right most element at the first position and start comparing nodes with the child nodes */ if (this.heap.length > 2) { this.heap[1] = this.heap[this.heap.length-1] this.heap.splice(this.heap.length - 1) // if (this.heap.length === 3) { if (this.heap[1] > this.heap[2]) { [this.heap[1], this.heap[2]] = [this.heap[2], this.heap[1]] } return smallest } // let current = 1 let leftChildIndex = current * 2 let rightChildIndex = current * 2 + 1 // while (this.heap[leftChildIndex] && this.heap[rightChildIndex] && (this.heap[current] > this.heap[leftChildIndex] || this.heap[current] > this.heap[rightChildIndex])) { if (this.heap[leftChildIndex] < this.heap[rightChildIndex]) { [this.heap[current], this.heap[leftChildIndex]] = [this.heap[leftChildIndex], this.heap[current]] current = leftChildIndex } else { [this.heap[current], this.heap[rightChildIndex]] = [this.heap[rightChildIndex], this.heap[current]] current = rightChildIndex } // leftChildIndex = current * 2 rightChildIndex = current * 2 + 1 } } // /* If there are only two elements in the array, we directly splice out the first element */ // else if (this.heap.length === 2) { this.heap.splice(1, 1) } else { return null } // return smallest } }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
80
Q

Лексическое окружение

A

Lexical Environment

Внутренний (скрытый) объект в JS, в котором хранится запись(environment record) всех локальных переменных в виде свойств и this, а также ссылка на внешнее лексическое окружение.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
81
Q

Литерал

A

literal

Литералы - это фиксированные значения, которые вы указываете в своём скрипте.
25 - литерал целого числа
23.8 - литерал дробного числа
‘js’ - литерал строки
[] - литерал массива
{} - литерал объекта

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
82
Q

Ложные значения

A

Falsy values
const falsyValues = [’‘(пустая строка без пробела), 0, null, undefined, NaN, false]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
83
Q

Матрица

A

Matrix
Матрица — двумерный массив, выглядящий как список столбцов и строк, на пересечении которых находятся элементы данных. Это прямоугольный массив, в котором количество строк и столбцов задает его размер. В математике их используют для компактной записи линейных алгебраических или дифференциальных уравнений.
Матрицы используют для описания вероятностей. Например, для ранжирования страниц в поиске Google при помощи алгоритма PageRank. В компьютерной графике — для работы с 3D-моделями и проецирования их на двумерный экран.

// Матрица 3x3 const matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]; console.log(matrix); // Доступ к элементу матрицы console.log(matrix[0][0]); // Выводит 1 console.log(matrix[1][2]); // Выводит 6 console.log(matrix[2][1]); // Выводит 8

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
84
Q

Метод preventdefault

A

При разработке таких типичных элементов интерфейса, как форма или попап, часто нужно изменить поведение браузера по умолчанию. Допустим, при клике по ссылке мы хотим, чтобы открывался попап, но вместо этого браузер будет автоматически переходить по адресу, указанному в атрибуте href. Или вот другая проблема — мы хотим перед отправкой формы проверять корректность введённых данных, но после нажатия на кнопку submit форма каждый раз будет отправляться на сервер, даже если там куча ошибок. Такое поведение браузера нам не подходит, поэтому мы научимся его переопределять.

Объект события и метод preventDefault

Событие — это какое-то действие, произошедшее на странице. Например, клик, нажатие кнопки, движение мыши, отправка формы и так далее. Когда срабатывает событие, браузер создаёт объект события Event. Этот объект содержит всю информацию о событии. У него есть свои свойства и методы, с помощью которых можно эту информацию получить и использовать. Один из методов как раз позволяет отменить действие браузера по умолчанию — preventDefault().
Event можно передать в функцию-обработчик события и в ней указать инструкции, которые должны быть выполнены, когда оно сработает. При передаче объекта события в обработчик обычно используется сокращённое написание — evt.

Мы хотим при клике на ссылку click-button добавлять элементу с классом content класс show. Он сделает попап видимым, поменяв значение свойства display с none на block. Напишем логику добавления этого класса с помощью JavaScript:

// Находим на странице кнопку и попап const button = document.querySelector('.click-button'); const popup = document.querySelector('.content'); // // Навешиваем на кнопку обработчик клика button.onclick = function (evt) { // Отменяем переход по ссылке evt.preventDefault(); // // Добавляем попапу класс show, делая его видимым popup.classList.add('show'); };

Если мы уберём строку evt.preventDefault(), вместо попапа откроется отдельная страница pop-up.html, адрес которой прописан в атрибуте href у ссылки. Такая страница нужна, потому что мы хотим, чтобы вся функциональность сайта была доступна, если скрипт по какой-то причине не будет загружен. Именно поэтому мы изначально реализовали кнопку с помощью тега a, а не button.

Не для всех событий можно отменить действие по умолчанию. Например, событие прокручивания страницы scroll проигнорирует попытки отменить его. Чтобы узнать, можно отменить действие по умолчанию или нет, нужно обратиться к свойству cancelable объекта Event. Оно будет равно true, если событие можно отменить, и false — в обратном случае.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
85
Q

Метод массива .filter()

A

Метод массива .filter() позволяет получить новый массив, отфильтровав элементы с помощью переданной колбэк-функции. Колбэк-функция будет вызвана для каждого элемента массива и по результату функции примет решение включать этот элемент в новый массив или нет.

const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] const evenOnly = nums.filter(function (n) { const remainder = n % 2 return remainder === 0 }) Результат будет [2, 4, 6, 8, 10].

Аналогично методу .forEach(), методу .filter() необходимо передать аргументом функцию. Главное отличие — функция должна возвращать boolean, т. е. результатом должен быть true или false. Такие функции называют предикатами.
Функция, которую мы передаём в метод .filter(), принимает три параметра:

  • item — элемент массива в текущей итерации;
  • index — индекс текущего элемента;
  • arr — сам массив, который мы перебираем.

В новом массиве отфильтрованные элементы будут находиться в том же порядке, в котором они были в исходном массиве.
💡 .filter() возвращает новый массив, при этом исходный массив никак не изменится.
💡 Из-за того, что JavaScript имеет динамическую типизацию, то нам ничего не мешает возвращать какое угодно значение из функции. В этом случае JavaScript сам определит его истинность. Стоит помнить, что значения 0, undefined, null и пустая строка ‘’ считаются ложными и равны false.
В JavaScript функция, в которой нет явного возвращаемого значения (т. е. нет return) все равно возвращает undefined. Потому, если забыть вернуть результат в функции в методе .filter(), то в результате получим пустой массив, так как отфильтруются все элементы. Получим [], потому что undefined считается как false.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
86
Q

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

A

Методы для добавления/удаления элементов массива:

  • push(...items) – добавляет элементы в конец массива.
  • pop() – извлекает элемент с конца массива.
  • unshift(...items) – добавляет элементы в начало массива.
  • shift() – извлекает элемент с начала массива.
  • splice(pos, deleteCount, ...items) – начиная с индекса pos, удаляет deleteCount элементов и вставляет items.
  • slice(start, end) – создаёт новый массив, копируя в него элементы с позиции start до end (не включая end).
  • concat(...items) – возвращает новый массив: копирует все элементы текущего массива и добавляет к нему items. Если какой-то из items является массивом, то его элементы будут добавлены по отдельности.

Методы для поиска среди элементов массива:

  • indexOf(item, pos) – ищет item, начиная с позиции pos, и возвращает его индекс или -1, если ничего не найдено.
  • lastIndexOf(item, pos) – работает аналогично indexOf, но ищет с конца массива.
  • includes(value) – возвращает true, если в массиве имеется элемент value, и false, если элемент не найден.
  • find/filter(func) – фильтрует элементы с помощью функции и возвращает первое/все значения, для которых функция возвращает true.
  • findIndex(func) – похож на find, но возвращает индекс элемента вместо значения.

Методы для перебора элементов массива:

  • forEach(func) – вызывает функцию для каждого элемента массива. Не возвращает результат.

Методы для преобразования и изменения массива:

  • map(func) – создаёт новый массив из результатов вызова функции для каждого элемента.
  • sort(func) – сортирует массив «на месте» и возвращает изменённый массив.
  • reverse() – меняет порядок следования элементов на противоположный “на месте” и возвращает изменённый массив.

Методы для преобразования массива в строку и обратно:

  • split()/join() – преобразуют строку в массив и обратно.

Методы для вычисления одного значения на основе всего массива:

  • reduce(func, initial)/reduceRight(func, initial) – вычисляют одно значение на основе всего массива, вызывая функцию для каждого элемента и передавая промежуточный результат между вызовами.

Дополнительные методы массивов:

  • Array.isArray(arr) - проверяет, является ли arr массивом.

Важно: Методы sort, reverse и splice изменяют исходный массив.

Другие методы:

  • arr.some(fn) / arr.every(fn) - проверяет массив. Функция fn вызывается для каждого элемента массива аналогично методу map. Если какой-либо/все результаты вызовов являются true, то метод some возвращает true, иначе false. Эти методы ведут себя примерно так же, как логические операторы || и &&: если fn возвращает истинное значение, arr.some() немедленно возвращает true и прекращает перебор остальных элементов; если fn возвращает ложное значение, arr.every() немедленно возвращает false и также прекращает перебор остальных элементов.

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

function arraysEqual(arr1, arr2) { return arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]); } alert(arraysEqual([1, 2], [1, 2])); // true

  • arr.fill(value, start, end) – заполняет массив повторяющимися value, начиная с индекса start до end.
  • arr.copyWithin(target, start, end) – копирует свои элементы, начиная с индекса start и заканчивая end, в заданную позицию target (перезаписывает существующие элементы).
  • arr.flat(depth) / arr.flatMap(fn) – создают новый плоский массив из многомерного массива.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
87
Q

Методы объектов

A

Статические методы объекта - методы, которые предварительно определены и вызываются в классе объектов.

  • Object.keys(obj) – возвращает массив ключей.
  • Object.values(obj) – возвращает массив значений.
  • Object.entries(obj) – возвращает массив пар [ключ, значение].

Пример обхода массива значений с помощью цикла for...of:

for (let value of Object.values(user)) { alert(value); // John, затем 30 }

Метод Object.fromEntries(array) - преобразует массив в объект. Пример использования:

Object.fromEntries(Object.entries(prices).map(([key, value]) => [key, value * 2]));

Методы экземпляра — это методы, встроенные в объекты, которые работают с конкретным экземпляром объекта, а не с классом объекта.

  • Object.prototype.hasOwnProperty() возвращает логическое значение, указывающее, имеет ли объект указанное свойство.

const object1 = {}; object1.property1 = 42; console.log(object1.hasOwnProperty('property1')); // Ожидаемый результат: true

Метод Object.create() создаёт новый объект с указанным прототипом и свойствами.

Метод Object.assign() используется для копирования перечисляемых и собственных свойств из одного или более исходных объектов в целевой объект. После копирования он возвращает целевой объект.

var o1 = { a: 1 }; var o2 = { [Symbol('foo')]: 2 }; var obj = Object.assign({}, o1, o2); console.log(obj); // { a: 1, [Symbol("foo")]: 2 }

Object.preventExtensions(объект) предотвращает добавление новых свойств к объекту (то есть, предотвращает расширение этого объекта в будущем).

Object.isExtensible(объект) - метод, который позволяет определить, можно ли расширять объект, и возвращает логическое значение.

Метод Object.freeze() предотвращает модификацию свойств и значений объекта, а также добавление и удаление свойств объекта.

Метод Object.isFrozen() позволяет определить, был ли объект заморожен или нет, и возвращает логическое значение.

Метод Object.seal() предотвращает добавление новых свойств объекта, но позволяет изменять существующие свойства.

Object.isSealed(объект) - метод, который позволяет определить, запечатан ли объект, и возвращает логическое значение.

Метод Object.getPrototypeOf() используется для получения внутреннего скрытого [[Prototype]] объекта, также доступного через свойство \_\_proto\_\_.
Существует также связанный с ним метод Object.setPrototypeOf(), который добавляет один прототип к другому объекту. Однако рекомендуется использовать Object.create(), поскольку он является более быстрым и эффективным.

Метод Object.defineProperty() определяет новое или изменяет существующее свойство напрямую на объекте, и возвращает этот объект.

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

Object.defineProperty(объект, свойство, описатель);

Object.defineProperty(объект, свойство, {value : значение});

Object.defineProperty(person, "language", {writable:false}); // делаем свойство language только для чтения

Метод Object.defineProperties() позволяет добавлять или изменять несколько свойств объекта в одном вызове.

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

Object.defineProperties(объект, описатель);

  • writable : true // Значение свойства можно изменять
  • enumerable : true // Свойство может перечисляться
  • configurable : true // Свойство может настраиваться

// Определение геттера get: function() { return language } // Определение сеттера set: function(value) { language = value }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
88
Q

Методы строк

A

Есть три типа кавычек. Строки, использующие обратные кавычки, могут занимать более одной строки в коде и включать выражения ${...}. Строки в JavaScript кодируются в UTF-16. Есть специальные символы, такие как разрыв строки \n.

Для получения символа используйте [] или метод at().

slice(start, end) извлекает часть строки и возвращает новую строку без изменения оригинальной строки.

Для того, чтобы перевести строку в нижний или верхний регистр, используйте toLowerCase()/toUpperCase().

Для поиска подстроки используйте indexOf()/lastIndexOf() или includes()/startsWith()/endsWith(), когда необходимо только проверить, есть ли вхождение.

Чтобы сравнить строки с учётом правил языка, используйте localeCompare().

concat() объединяет две или более строки и возвращает одну строку.

  • split() - Разбивает строку на массив по указанному разделителю, который может быть подстрокой или регулярным выражением.
  • str.trim() - Убирает пробелы в начале и конце строки.
  • str.repeat(n) - Повторяет строку n раз.
  • charCodeAt - Возвращает числовое значение Юникода для символа по указанному индексу. Обратите внимание, что у символов в верхнем и нижнем регистрах разные коды.
  • fromCharCode - Преобразует числовые значения Юникода в соответствующие символы.
  • search - Проверяет, содержит ли строка указанное значение или совпадение с регулярным выражением и возвращает индекс начала совпадения.
  • replace - Ищет в строке указанное значение или совпадение с регулярным выражением и возвращает новую строку, в которой произведена замена на второй параметр. Можно заменить найденные значения другой строкой или передать функцию для дополнительной обработки совпадений.
  • padEnd - Добавляет отступы до тех пор, пока строка не достигнет заданной длины, указанной первым параметром. Вторым параметром можно указать другой символ вместо пробела.
  • padStart - Добавляет в начале отступы, пока строка не достигнет длины, заданной первым параметром. Вторым параметром можно указать другой символ вместо пробела.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
89
Q

Методы чисел

A

Чтобы писать числа с большим количеством нулей: Используйте краткую форму записи чисел – “e”, с указанным количеством нулей. Например: 123e6 это 123 с 6-ю нулями 123000000. Отрицательное число после “e” приводит к делению числа на 1 с указанным количеством нулей. Например: 123e-6 это 0.000123 (123 миллионных).

Для других систем счисления: Можно записывать числа сразу в шестнадцатеричной (0x), восьмеричной (0o) и бинарной (0b) системах счисления. parseInt(str, base) преобразует строку в целое число в соответствии с указанной системой счисления: 2 ≤ base ≤ 36. num.toString(base) представляет число в строковом виде в указанной системе счисления base.

Для проверки на NaN и Infinity: isNaN(value) преобразует аргумент в число и проверяет, является ли оно NaN. Number.isNaN(value) проверяет, является ли аргумент числом, и если да, то проверяет, является ли оно NaN.

isFinite(value) преобразует аргумент в число и проверяет, что оно не является NaN/Infinity/-Infinity.
Number.isFinite(value) проверяет, является ли аргумент числом, и если да, то проверяет, что оно не является NaN/Infinity/-Infinity.

Для преобразования значений типа 12pt и 100px в число: Используйте parseInt/parseFloat для «мягкого» преобразования строки в число, данные функции по порядку считывают число из строки до тех пор пока не возникнет ошибка.

Для дробей: Используйте округления Math.floor, Math.ceil, Math.trunc, Math.round или num.toFixed(precision). Помните, что при работе с дробями происходит потеря точности.

Ещё больше математических функций:
Также есть математические функции с помощью объекта Math.
Функция abs() возвращает абсолютное значение числа.
Функции min() и max() возвращают соответственно минимальное и максимальное значение из набора чисел.
Функция ceil() округляет число до следующего наибольшего целого числа.
Функция floor() округляет число до следующего наименьшего целого числа
Функция round() округляет число до следующего наименьшего целого числа, если его десятичная часть меньше 0.5. Если же десятичная часть равна или больше 0.5, то округление идет до ближайшего наибольшего целого числа
Функция random() возвращает случайное число с плавающей точкой их диапазона от 0 до 1
Функция pow() возвращает число в определенной степени. Например, возведем число 2 в степень 3
Функция sqrt() возвращает квадратный корень числа
Функция log() возвращает натуральный логарифм числа

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
90
Q

Механизм обхода лексического окружения

A

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

В JavaScript лексическое окружение создается при выполнении функции или блока кода. Оно состоит из двух основных компонентов: содержащего окружения и ссылки на внешнее окружение.

Содержащее окружение содержит все локальные переменные, функции и объекты, объявленные внутри функции или блока кода. Ссылка на внешнее окружение указывает на область видимости, в которой была создана функция или блок кода.

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

Вот пример, иллюстрирующий механизм обхода лексического окружения:

function outer() { var outerVar = 'I am in the outer function'; // function inner() { var innerVar = 'I am in the inner function'; console.log(innerVar); // Output: I am in the inner function console.log(outerVar); // Output: I am in the outer function console.log(globalVar); // Output: I am a global variable } // inner(); } // var globalVar = 'I am a global variable'; outer();

В этом примере у нас есть функция outer(), которая содержит переменную outerVar, и вложенная функция inner(), которая содержит переменную innerVar. Внутри функции inner() мы можем обращаться и получать доступ к переменным innerVar и outerVar, а также к глобальной переменной globalVar.

Пример демонстрирует, как обходится лексическое окружение: при обращении к переменной innerVar, оно сначала ищется внутри функции inner(), а затем во внешнем окружении - функции outer(). Аналогично, при обращении к переменной outerVar, оно сначала ищется внутри функции outer(), а затем в глобальной области видимости.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
91
Q

Модули

A

Modules
Модули позволяют объединять (использовать) код из разных файлов и избавляют нас от необходимости держать весь код в одном большом файле. По мере роста нашего приложения, мы обычно хотим разделить его на много файлов, так называемых «модулей». Модуль обычно содержит класс или библиотеку с функциями.

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

Зачем нужны модули:
- Ремонтопригодность
- Возможность повторного использования
- Пространство имен
- Библиотеки для динамической подгрузки модулей

Например:
- AMD – одна из самых старых модульных систем, изначально реализована библиотекой require.js.
- CommonJS – модульная система, созданная для сервера Node.js.
- UMD – ещё одна модульная система, предлагается как универсальная, совместима с AMD и CommonJS.

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

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

Отличия модулей от «обычных» скриптов

В модулях всегда используется режим use strict. Например, присваивание к необъявленной переменной вызовет ошибку.

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

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

В модуле на верхнем уровне this не определён (undefined).

Модули всегда выполняются в отложенном (deferred) режиме, точно так же, как скрипты с атрибутом defer. Это верно и для внешних и встроенных скриптов-модулей.

Объект import.meta содержит информацию о текущем модуле. Содержимое зависит от окружения. В браузере он содержит ссылку на скрипт или ссылку на текущую веб-страницу, если модуль встроен в HTML.

<script type="module"> alert(import.meta.url); // ссылка на html страницу для встроенного скрипта </script>

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

Браузер загружает и анализирует скрипты модулей автоматически.

В реальной жизни часто используется сборщик Webpack для объединения модулей. Это позволяет улучшить производительность и получить другие “плюшки” в работе с модулями.

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

Перед объявлением класса/функции/…:
- export [default] class/function/variable ...

Отдельный экспорт:
- export {x [as y], ...}

Реэкспорт:
- export {x [as y], ...} from "module"
- export * from "module" (не реэкспортирует export default)
- export {default [as y]} from "module" (реэкспортирует только export default)

Импорт:
Именованные экспорты из модуля:
- import {x [as y], ...} from "module"

Импорт по умолчанию:
- import x from "module"
- import {default as x} from "module"

Все сразу:
- import * as obj from "module"

Только подключить модуль (его код запустится), но не присваивать его переменной:
- import "module"

Мы можем разместить операторы import/export в начале или в конце скрипта, это не имеет значения.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
92
Q

Модули пакеты

A

Packages
К модулям-пакетам относятся папки с кодом, описываемые при помощи находящегося в них файла package.json. С модулями-пакетами удобно работать при помощи менеджеров пакетов, таких как npm или yarn. Если мы хотим использовать уже написанные кем-то модули-пакеты (частый способ использования кода других разработчиков), их нужно установить, затем подключить, затем использовать.
Установка модуля-пакета при помощи npm осуществляется командой

npm install <имя модуля>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
93
Q

Модуль Path

A

Модуль Path
Одним из стандартных модулей является path. Модуль path предназначен для того, чтобы работать с путями в Node.js. При помощи него можно получить имя файла, расширение файла, имя папки, указать путь к файлу.
Чтобы использовать path, его необходимо подключить:

`const path = require(‘path’);

console.log(path.basename(__filename)); // index.js - имя файла на Windows, полный путь к файлу на POSIX-системах
console.log(path.dirname(__filename)); // C:\Users\Admin\Desktop\nodejs-basic - название папки
console.log(path.extname(__filename)); // .js - расширение файла
console.log(path.parse(__filename)); // возвращает объект в котором указывается корень диска, имя папки, имя файла, расширение файла, имя файла без расширения
path.join() объединяет заданные сегменты пути вместе, используя в качестве разделителя разделитель данной конкретной платформы (для Linux - прямой слэш, для Windows - обратный слэш), результат - относительный путь
console.log(path.join(__dirname, ‘test’, ‘second.html’)); // вернет C:\Users\Admin\Desktop\nodejs-basic\test\second.html
path.resolve() преобразует последовательность путей или сегментов пути в абсолютный путь справа налево и нормализует его: если в некоторых сегментах пути указываются слэши, а в некоторых нет, всё равно будет сгенерирован правильный путь.
console.log(path.resolve(__dirname, ‘./test’, ‘/second.html’));`

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
94
Q

NaN

A

Не число - NaN (not a number)

Говорит о том, что выполнена бессмысленная операция (деление строки на число, бесконечности на бесконечность и тд).
Относится к типу Number

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
95
Q

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

A

Variable scope

Область видимости в JavaScript определяет, какие переменные доступны вам. Существуют два типа областей видимости: глобальная и локальная.

Глобальная область видимости — переменные и функции, объявленные в глобальном пространстве имен, имеют глобальную область видимости и доступны из любого места в коде. Существует вероятность пересечения имен, когда двум или более переменным присваивают одинаковое имя. Если переменные объявляются через const или let, то каждый раз, когда будет происходить пересечение имён, будет показываться сообщение об ошибке.
Если объявлять переменные через var, то вторая переменная после объявления перепишет первую.

Локальная область видимости включает:

Функциональная область видимости (область видимости функции) — переменные, функции и параметры, объявленные внутри функции, доступны только внутри этой функции.

Блочная область видимости — переменные (объявленные с помощью ключевых слов «let» и «const») внутри блока ({ }), доступны только внутри него. Блочная область видимости является частным случаем области видимости функции, т.к. функции объявляются с фигурными скобками (кроме случаев использования стрелочных функций с неявным возвращением значения).

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

Функции, объявленные как «function declaration» (прим. перев.: функция вида function имя(параметры) {…}), всегда поднимаются наверх в текущей области видимости. Если же функция объявляется как «function expression» (функциональное выражение) (прим. перев.: функция вида const f = function (параметры) {…}), то такая функция не поднимается в текущей области видимости.

Вложенные области видимости
Когда функция объявляется в другой функции, то внутренняя функция имеет доступ к переменным внешней функции. Такой поведение называется разграничением лексических областей видимости.

В тоже время внешняя функция не имеет доступа к переменным внутренней функции.

function outerFunction () { const outer = I’m the outer function!; // function innerFunction() { const inner = I’m the inner function!; console.log(outer); // I'm the outer function! } // console.log(inner); // Ошибка, inner не определена }

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

function outerFunction () { const outer = I see the outer variable!; // function innerFunction() { console.log(outer); } // return innerFunction; } // outerFunction()(); // I see the outer variable!

Так как внутренняя функция является возвращаемым значением внешней функции, то можно немного сократить код, совместив возврат значения с объявлением функции.

function outerFunction () { const outer = I see the outer variable!; // return function innerFunction() { console.log(outer); } } // outerFunction()(); // I see the outer variable!

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

  • контроля побочных эффектов;
  • создания приватных переменных.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
96
Q

Объявить переменную

A

declare variable

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

const name = "Nastya"; let age = 31;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
97
Q

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

A

VAR*
- Поддерживает повторное объявление переменных. Количество объявлений не ограничено.

var greeting = 'Hello world!'; var greeting = 'Hello Mary!'; // значение переменной теперь 'Hello Mary!'

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

{ var varVrb = 2; } console.log(varVrb); // 2

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

varVrb = 3; var varVrb;

  • Значение может быть определено позже. Переменную можно объявить без присваивания значения, а затем присвоить значение позже.

var greeting; greeting = 'Hello world!';

  • Значение может быть переопределено в будущем. После объявления переменную с помощью var можно переопределить, присвоив ей новое значение.

var greeting = 'Hello world!'; greeting = 'Hello Mary!'; // значение теперь 'Hello Mary!'

const и let

  • Не поддерживают повторное объявление. Если попытаться повторно объявить переменную с использованием const или let, будет выдана ошибка:

let greeting = 'Hello world!'; let greeting = 'Hello Karl!'; // SyntaxError: Identifier 'greeting' has already been declared

  • Соблюдают блочную область видимости. Переменные, объявленные с помощью const или let, видны только внутри блока, в котором они объявлены:

{ const constVrb = 1; let letVrb = 2; } console.log(constVrb); // ReferenceError: constVrb is not defined console.log(letVrb); // ReferenceError: letVrb is not defined

  • Не поддерживают hoisting. Объявление переменных с помощью const или let остается в области видимости, где они были объявлены. Поэтому необходимо сначала объявить переменную, а затем присвоить ей значение:

letVrb = 2; // ReferenceError: Cannot access 'letVrb' before initialization let letVrb; console.log(constVrb); // ReferenceError: constVrb is not defined console.log(letVrb); // ReferenceError: letVrb is not defined

  • Значение должно быть определено при объявлении переменной (сразу) для константной переменной const:

const greeting = 'Hello world!';

  • Значение константной переменной const не может быть переопределено после инициализации:

const greeting = 'Hello world!'; greeting = 'Hello Marry!'; // TypeError: Assignment to constant variable.

Итого:
- Переменные, объявленные через var, могут быть глобальными или иметь область видимости в рамках функции; let и const имеют блочную область видимости.
- var-переменные могут быть как обновлены, так и переопределены внутри области видимости; let-переменные можно обновлять, но не переопределять; const-переменные нельзя ни обновлять, ни переопределять.
- Со всеми ними осуществляется поднятие наверх области видимости. Но если var-переменные при этом инициализируются как undefined, let и const не инициализируются.
- В то время как var и let можно объявить, но не инициализировать, const необходимо инициализировать во время объявления.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
98
Q

Объясни разницу между изменяемыми и неизменяемыми значениями

A

Значения примитивных типов (например, строка или число) не могут быть изменены после того, как попали в память.

Значения объектных типов (объекты, массивы) могут изменяться в ходе работы программы.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
99
Q

Объясни разницу между синхронными и асинхронными функциями

A

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

С другой стороны, есть асинхронный способ выполнения функций, когда мы не блокируем весь интерфейс благодаря тому, что не дожидаемся выполнения функции, а подписываемся на событие с передачей обратного вызова. Ну, или мы можем иметь дело с обещанием или с прочими внешними API вроде setTimeout.

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
100
Q

Оператор и операнд

A

Operator and operand

console.log(2 + 8);

Оператор +, -, / и тд. Операнды 2 и 8.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
101
Q

Операторы инкремент и декремент

A

Increment and decrement operators

Унарные операторы, которые добавляют или вячитают единицу от своего операнда.

++ инкремент
– декремент
– 1 предекремент
++1 преинкремент
1 – постдекремени
1 ++ постинкремент

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
102
Q

Операторы сравнения

A

Comparison operators
Операторы сравнения возвращают значения логического типа.
Строки сравниваются посимвольно в лексикографическом порядке.
Значения разных типов при сравнении приводятся к числу. Исключением является сравнение с помощью операторов строгого равенства/неравенства.
Значения null и undefined равны == друг другу и не равны любому другому значению.
Будьте осторожны при использовании операторов сравнений вроде > и < с переменными, которые могут принимать значения null/undefined. Хорошей идеей будет сделать отдельную проверку на null/undefined.
Значение NaN считается не равным никакому другому значению, включая само себя. При его наличии оператор равенства всегда возвращает false, а оператор неравенства – true.
Если оба операнда являются объектами, то они сравниваются, чтобы выяснить, один ли это объект. Если да, возвращается true, иначе – false.

  • == - оператор равенства. Сравнивает значения с приведением типов, поэтому может быть неоднозначным. Например, 1 == '1' вернет true, так как значения равны после приведения типов.
  • === - оператор строгого равенства. Сравнивает значения без приведения типов. В этом случае, 1 === '1' вернет false, так как значения имеют различные типы.
  • != - оператор неравенства. Сравнивает значения с приведением типов. Например, 1 != '1' вернет false, так как значения равны после приведения типов.
  • !== - оператор строгого неравенства. Сравнивает значения без приведения типов. В этом случае, 1 !== '1' вернет true, так как значения имеют различные типы.
  • > - оператор больше. Проверяет, является ли первое значение больше второго.
  • < - оператор меньше. Проверяет, является ли первое значение меньше второго.
  • >= - оператор больше или равно. Проверяет, является ли первое значение больше или равно второму.
  • <= - оператор меньше или равно. Проверяет, является ли первое значение меньше или равно второму.
  • && - оператор логического И. Возвращает true, если оба операнда истинны.
  • || - оператор логического ИЛИ. Возвращает true, если хотя бы один из операндов истинен.
  • ! - оператор логического отрицания. Инвертирует значение операнда.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
103
Q

Очередь (Структуры данных)

A

Queue
Как и стек очереди могут быть реализованы с помощью связного списка или массива.
Очереди — это FIFO-структуры данных (first in, first out).
Аналог очереди - очередь в магазине: первого покупателя обслужат первым
Элементы удаляются из головы, а добавляются в хвост.
Эффективность списка, стека, очереди («О» большое):
Индексирование: O(n).
Поиск: O(n).
Двоичный поиск: O(n).
Вставка: O(1).

Основные операции:
добавление нового элемента в конец очереди (enqueue);
удаление элемента из начала очереди (dequeue);
чтение элемента из начала очереди без удаления (peek).

Как и стек, очередь может быть реализована как на базе массива, так и на базе связного списка. И опять же, массивы в JavaScript фактически могут работать как очереди, благодаря встроенным методам.

class Queue { constructor() { this.linkedList = new LinkedList(); } // isEmpty() { return !this.linkedList.head; } // peek() { if (!this.linkedList.head) { return null; } // return this.linkedList.head.value; } // enqueue(value) { this.linkedList.append(value); } // dequeue() { const removedHead = this.linkedList.deleteHead(); return removedHead ? removedHead.value : null; } }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
104
Q

Параметры по умолчанию

A

Default Parameters
Параметры функции по умолчанию позволяют инициализировать параметры со значениями по умолчанию, если значение не передано или не определено.

function add(a = 0, b = 0){ return a + b } // если мы не присвоим переменным "a" и "b" какие-нибудь значения, они будут равняться 0 add(1) // 1

Инициализаторы параметров по умолчанию живут в своей собственной области, которая является родителем области, созданной для тела функции.

function f(a = go()) { function go() { return ":P"; } } f(); // ReferenceError: go is not defined

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
105
Q

Параметры функции

A

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

имя функции ( параметр1 , параметр2 , параметр3 ) { // тело функции }

Значение, которое мы передаем функции, называется аргументом функции. Аргументы передаются функции, когда мы ее вызываем.
Вы можете определить любое количество параметров для вашей функции JavaScript, и количество добавляемых аргументов не должно совпадать с количеством параметров.
Вы также можете определить значения параметров по умолчанию при объявлении функций.
Параметры оцениваются в JavaScript слева направо.
Функция JavaScript не выдаст никакой ошибки, если переданные вами аргументы больше или меньше количества параметров. Недостающие параметры будут определены как undefined,а лишние - будут проигнорированы.

Существует еще один метод для доступа к аргументам внутри нашей функции, который называется « Arguments Object ». Объект Arguments содержит значения аргументов в объекте с механизмом, подобным массивам.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
106
Q

Передать динамическое количество параметров функции

A

В JavaScript есть несколько способов передачи динамического количества параметров функции:

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

function sum() { let total = 0; for (let i = 0; i < arguments.length; i++) { total += arguments[i]; } return total; } // console.log(sum(1, 2, 3)); // Output: 6 console.log(sum(1, 2, 3, 4, 5)); // Output: 15

  1. Оператор “Rest” (...): Можно использовать оператор “Rest” для сбора дополнительных аргументов в виде массива. Оператор “Rest” должен быть последним параметром функции. Например:

function sum(...numbers) { let total = 0; for (let i = 0; i < numbers.length; i++) { total += numbers[i]; } return total; } // console.log(sum(1, 2, 3)); // Output: 6 console.log(sum(1, 2, 3, 4, 5)); // Output: 15

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
107
Q

Передача параметров по значению и по ссылке

A

Передача параметров по значению

Строки, числа, логические значения передаются в функцию по значению. Иными словами при передаче значения в функцию, эта функция получает копию данного значения. Рассмотрим, что это значит в практическом плане:

function change(x){ x = 2 * x; console.log("x in change:", x); } // var n = 10; console.log("n before change:", n); // n before change: 10 change(n); // x in change: 20 console.log("n after change:", n); // n after change: 10

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

Передача по ссылке

Объекты и массивы передаются по ссылке. То есть функция получает сам объект или массив, а не их копию.

function change(user){ user.name = "Tom"; } // var bob ={ name: "Bob" }; console.log("before change:", bob.name); // Bob change(bob); console.log("after change:", bob.name); // Tom

В данном случае функция change получает объект и меняет его свойство name. В итоге мы увидим, что после вызова функции изменился оригинальный объект bob, который передавался в функцию.

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

function change(user){ // полная переустановка объекта user= { name:"Tom" }; } // var bob ={ name: "Bob" }; console.log("before change:", bob.name); // Bob change(bob); console.log("after change:", bob.name); // Bob

То же самое касается массивов.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
108
Q

Перемешивание Фишера-Ейтса

A

Fisher-Yates shuffle algorithm

function fyShuffle(arr) { let i = arr.length; while (--i > 0) { let randIndex = Math.floor(Math.random() * (i + 1)); [arr[randIndex], arr[i]] = [arr[i], arr[randIndex]]; } return arr; }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
109
Q

Поверхностное и глубокое копирование

A

Shallow or deep clone

Глубокое копирование
Если необходимо полностью скопировать сложную структуру данных, например, массив с объектами, то нужно делать глубокое (deep) или полное копирование данных. 1. JavaScript не содержит функций для глубокого копирования, лучший вариант сделать глубокую копию — сериализовать структуру в JSON и тут же распарсить.
const newArr = JSON.parse(JSON.stringify(arr))

  1. Для глубокой копии можно написать функцию`const deepClone = obj => { if (obj === null) return null; // Создаем поверхностный клона оригинала. let clone = Object.assign({}, obj);// // Определяем, какие пары ключ-значение // необходимо глубоко клонировать. Object.keys(clone).forEach( key => (clone[key] = typeof obj[key] === “object” ? deepClone(obj[key]) : obj[key]) );// // Проверяем является ли obj массивом и не пустой ли он. return Array.isArray(obj) && obj.length // Если obj массив и он не пуст, тогда // указываем объекту clone длину исходного массива что бы // конвертировать clone в массив и вернуть его. ? (clone.length = obj.length) && Array.from(clone) // Если obj пустой массив,
    : Array.isArray(obj)
    // то возвращаем его
    ? Array.from(obj)
    // в других случаях obj это объект и мы возвращаем копию clone.clone;
    };
    //
    // Пример:
    const a = { foo: “bar”, obj: { a: 1, b: 2 } };
    const b = deepClone(a);
    // a !== b true
    // a.obj !== b.obj true`
  2. Воспользоваться готовой библиотекой. Например, функцию глубокого копирования содержит популярная библиотека утилит lodash.
  3. Использовать structuredClone

const obj = { name: "Mike", friends: [{ name: "Sam" }] }; const clonedObj = structuredClone(obj); console.log(obj === clonedObj); // false console.log(obj.friends === clonedObj.friends); // false

Неглубокое копирование

  1. Spread syntax, появившийся в ES6, позволяет «вытаскивать» перебираемые элементы из своего контейнера.
  2. Клонировать/копировать содержимое массива, можно через метод slice, передав 0 в качестве первого аргумента:
    var clone = myArray.slice(0);
    Код выше создает копию исходного массива; имейте в виду, если в вашем массиве существуют объекты - они хранятся как ссылки;
    т.е. код выше не делает “deep” клонирование содержимого массива.
  3. Function.prototype.apply()

var first = [1, 2, 3]; var second = [4, 5]; Array.prototype.push.apply(first, second); console.log(first); //[1,2,3,4,5] console.log(second); // [4,5]

  1. Другой способ с использованием Array.from:
    const cloneSheeps = Array.from(sheeps)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
110
Q

Поднятие (всплытие)

A

Hoisting

Механизм, из-за которого переменные и объявления функций передвигаются вверх своей области видимости перед тем, как код будет выполнен.
Код выполняется в рамках контекста выполнения (среды, в которой выполняется код). Контекст выполнения имеет две фазы — компиляция и выполнение.
1. В фазе компиляции function declaration и переменные, объявленные с помощью ключевого слова «var» поднимаются в самый верх глобальной (или функциональной) области видимости.
2. В фазе выполнения переменным присваиваются значения, а функции вызываются или выполняются.

temporal dead zone
Временная мертвая зона (TDZ) — это область блока, в которой переменная недоступна до момента, когда ей будет инициализировано значение.
Блок представляет собой пару фигурных скобок ({…}), используемых для группировки.
Инициализация происходит, когда вы присваиваете начальное значение переменной.
Предположим, вы пытаетесь получить доступ к переменной до ее полной инициализации. В таком случае JavaScript выдаст ошибку ReferenceError.
Если коротко, мы должны сначала инициализировать переменную значением, а потом уже обращаться к ней в коде.

let bestFood = "Vegetable Fried Rice"; // bestFood’s TDZ ends here console.log(bestFood);

Основное различие между временной мертвой зоной переменной var, let, и constпеременной заключается в том, когда заканчивается их TDZ. TDZ переменной let(или const) заканчивается, когда JavaScript полностью инициализирует ее значением, указанным при ее объявлении. А var TDZ переменной заканчивается сразу после ее подъема, а не тогда, когда переменная полностью инициализируется значением, указанным при ее объявлении.

Область видимости — это место, где (или откуда) мы имеем доступ к переменным или функциям. JS имеем три типа областей видимости: глобальная, функциональная и блочная (ES6).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
111
Q

Преобразование типов

A
  1. undefined:
    - В строку: String(undefined) дает результат "undefined".
    - В число: Number(undefined) дает результат NaN.
    - В логический тип: Boolean(undefined) дает результат false.
  2. null:
    - В строку: String(null) дает результат "null".
    - В число: Number(null) дает результат 0.
    - В логический тип: Boolean(null) дает результат false.
  3. Булевый тип (true/false):
    - В строку: String(true) дает результат "true". String(false) дает результат "false".
    - В число: Number(true) дает результат 1. Number(false) дает результат 0.
    - В логический тип: Boolean(true) дает результат true. Boolean(false) дает результат false.
    - При преобразовании в объектный тип: Object(true) и Object(false) создают обертки объектов Boolean.
  4. Числовой тип:
    - В строку: String(123) дает результат "123".
    - В число: Number("123") дает результат 123. Если строка содержит некорректные символы или является пустой, результат будет NaN.
    - В логический тип: Любое число, кроме 0, NaN или пустой строки, преобразуется в true. Число 0, NaN или пустая строка преобразуются в false.
    - При преобразовании в объектный тип: Object(123) создает обертку объекта Number.

4.1. NaN:
- В строку: String(NaN) дает результат "NaN".
- В число: Number(NaN) дает результат NaN.
- В логический тип: Boolean(NaN) дает результат false.
- При преобразовании в объектный тип: Object(NaN) создает объектное представление числа NaN.

4.2. Infinity:
- В строку: String(Infinity) дает результат "Infinity".
- В число: Number(Infinity) дает результат Infinity.
- В логический тип: Boolean(Infinity) дает результат true.
- При преобразовании в объектный тип: Object(Infinity) создает объектное представление числа Infinity.

4.3. -Infinity:
- В строку: String(-Infinity) дает результат "-Infinity".
- В число: Number(-Infinity) дает результат -Infinity.
- В логический тип: Boolean(-Infinity) дает результат true.
- При преобразовании в объектный тип: Object(-Infinity) создает объектное представление числа -Infinity.

  1. Строковый тип:
    - В число: Number("123") дает результат 123. Если строка содержит некорреткные символы или является пустой, результат будет NaN.
    - В логический тип: Пустая строка преобразуется в false, а непустая строка преобразуется в true.
    - При преобразовании в объектный тип: Object("Hello") создает обертку объекта String со значением “Hello”.
  2. Объектный тип:
    - В строку: Объект вызывает метод toString(). Если метод toString() не переопределен, то возвращается строка “[object Object]”.
    - В число: Объект вызывает метод valueOf(). Если метод valueOf() не переопределен, то вызывается метод toString(), а затем результат пытается быть преобразован в число. Если преобразование не удается, результат будет NaN.
    - В логический тип: Любой объект, кроме null и undefined, преобразуется в true.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
112
Q

Потеря контекста

A

Как только метод передаётся отдельно от объекта – this теряется.

let user = { firstName: "Вася", sayHi() { alert(Привет, ${this.firstName}!); } }; setTimeout(user.sayHi, 1000); // Привет, undefined!

setTimeout получил функцию sayHi отдельно от объекта user (именно здесь функция и потеряла контекст). Метод setTimeout в браузере имеет особенность: он устанавливает this=window для вызова функции. Таким образом, для this.firstName он пытается получить window.firstName, которого не существует. В других подобных случаях this обычно просто становится undefined.

Решения:
1. функция обертка (user достаётся из замыкания, а затем вызывается его метод sayHi) - хуже

setTimeout(function() { user.sayHi(); // Привет, Вася! }, 1000); 2. или setTimeout(() => user.sayHi(), 1000); // Привет, Вася!

  1. привязать контекст с помощью bind - лучше
    В современном JavaScript у функций есть встроенный метод bind, который позволяет зафиксировать this.

let user = { firstName: "Вася", sayHi() { alert(Привет, ${this.firstName}!); } }; // let sayHi = user.sayHi.bind(user); // берём метод user.sayHi и привязываем его к user.Теперь sayHi – это «связанная» функция, которая может быть вызвана отдельно или передана в setTimeout (контекст всегда будет правильным). // sayHi(); // Привет, Вася! // setTimeout(sayHi, 1000); // Привет, Вася!

Интересно:
Если у объекта много методов и мы планируем их активно передавать, то можно привязать контекст для них всех в цикле через метод: bindAll

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
113
Q

Полифилы

A

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
114
Q

Полифил forEach

A

if (!Array.prototype.forEach) { // Проверяем, не был ли уже добавлен метод forEach // Array.prototype.myForEach = function(callback) { // Добавляем свой собственный метод myForEach в прототип массива // if (!this instanceof Array) { // Проверяем, является ли текущий объект массивом throw new Error("Isn't array"); // Если объект не является массивом, выбрасываем ошибку } // if (typeof callback !== "function") { // Проверяем, является ли callback функцией throw new Error("Callback isn't function"); // Если callback не является функцией, выбрасываем ошибку } // for (let i = 0; i < this.length; i += 1) { // Итерируем по элементам массива callback(this[i], i, this); // Вызываем callback для каждого элемента массива, передавая значение элемента, индекс и сам массив } }; }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
115
Q

Преобразование числа в двоичное и обратно в десятеричное

A

Двоичная система счисления — это позиционная система счисления с основанием 2. В этой системе счисления числа записываются с помощью двух символов: 0 и 1.

Из десятеричного в двоичное:

Функция toString(2) при использовании с числовым объектом возвращает двоичный эквивалент числового значения, как показано в примерах ниже.
(8).toString(2)// "1000" (25).toString(2)// "11001" (235).toString(2)// "11101011"

8..toString(2) - если нам надо вызвать метод непосредственно на числе, как toString в примере выше, то нам надо поставить две точки .. после числа. Если мы поставим одну точку: 123456.toString(36), тогда это будет ошибкой, поскольку синтаксис JavaScript предполагает, что после первой точки начинается десятичная часть.

Своя функция:

function convertDecToBinary(num) { const binary = []; while (num >= 1) { binary.unshift(num % 2); // получаем остаток от деления на 2 (1 или 0) и пушим в начало массива num = Math.floor(num / 2); // меняем num - делим пополам и округляем к меньшему } return +binary.join(""); // массив переводим в строку и делаем числом }

Из двоичного в десятеричное:

ES6 поддерживает двоичные числовые литералы для целых чисел, поэтому, если двоичная строка неизменяема, можно просто ввести ее как есть с префиксом 0b или 0B:
const binary = 0b1101000; // code for 104 console.log(binary); // prints 104

Функция parseInt(value,2) принимает строку и систему исчисления числа строки в качестве аргумента и возвращает целое число в десятичной
системе исчисления.
parseInt("1111", 2); //15

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
116
Q

Префиксное дерево (Структуры данных)

A

Prefix tree или trie

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

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

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
117
Q

Префиксный, инфиксный, постфиксный оператор

A

Prefix, infix, postfix operator

Префиксный +5
Инфиксный 3 + 5
Постфиксный 5 +

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
118
Q

Принцип DRY

A

don’t repeat yourself / не повторяйте себя
Если код не дублируется, то для изменения логики достаточно внесения исправлений всего в одном месте и проще тестировать одну (пусть и более сложную) функцию, а не набор из десятков однотипных. Следование принципу DRY всегда приводит к декомпозиции сложных алгоритмов на простые функции. А декомпозиция сложных операций на более простые (и повторно используемые) значительно упрощает понимание программного кода. Повторное использование функций, вынесенных из сложных алгоритмов, позволяет сократить время разработки и тестирования новой функциональности.

Следование принципу DRY приводит к модульной архитектуре приложения и к чёткому разделению ответственности за бизнес-логику между программными классами. А это — залог сопровождаемой архитектуры. Хотя чаще не DRY приводит к модульности, а уже модульность, в свою очередь, обеспечивает принципиальную возможность соблюдения этого принципа в больших проектах.
В рамках одного программного класса (или модуля) следовать DRY и не повторяться обычно достаточно просто. Также не требует титанических усилий делать это в рамках небольших проектов, где все разработчики «владеют» всем кодом системы. А вот в больших проектах ситуация с DRY несколько сложнее — повторы чаще всего появляются из-за отсутствия у разработчиков целостной картины или несогласованности действий в рамках команды. Следовать принципу «don’t repeat yourself» в рамках больших проектов не так просто, как это может показаться на первый взгляд.

От разработчиков требуется тщательное планирование архитектуры, а от архитектора или тимлида требуется наличие видения системы в целом и чёткая постановка задач разработчикам.
В проектировании DRY тоже имеет место — доступ к конкретному функционалу должен быть доступен в одном месте, унифицирован и сгруппирован по какому-либо принципу, а не «разбросан» по системе в произвольных вариациях. Этот подход пересекается с принципом единственной ответственности из пяти принципов SOLID, сформулированных Робертом Мартином.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
119
Q

Принцип KISS

A

Keep It Short and Simple
В проектировании следование принципу KISS выражается в том, что:
- не имеет смысла реализовывать дополнительные функции, которые не будут использоваться вовсе или их использование крайне маловероятно, как правило, большинству пользователей достаточно базового функционала, а усложнение только вредит удобству приложения;
- не стоит перегружать интерфейс теми опциями, которые не будут нужны большинству пользователей, гораздо проще предусмотреть для них отдельный «расширенный» интерфейс (или вовсе отказаться от данного функционала);
- бессмысленно делать реализацию сложной бизнес-логики, которая учитывает абсолютно все возможные варианты поведения системы, пользователя и окружающей среды, — во-первых, это просто невозможно, а во-вторых, такая фанатичность заставляет собирать «звездолёт», что чаще всего иррационально с коммерческой точки зрения.

В программировании следование принципу KISS можно описать так:
- не имеет смысла беспредельно увеличивать уровень абстракции, надо уметь вовремя остановиться;
- бессмысленно закладывать в проект избыточные функции «про запас», которые может быть когда-нибудь кому-либо понадобятся (тут скорее правильнее подход согласно принципу YAGNI);
- не стоит подключать огромную библиотеку, если вам от неё нужна лишь пара функций;
- декомпозиция чего-то сложного на простые составляющие — это архитектурно верный подход (тут KISS перекликается с DRY);
абсолютная математическая точность или предельная детализация нужны не всегда — большинство систем создаются не для запуска космических шаттлов, данные можно и нужно обрабатывать с той точностью, которая достаточна для качественного решения задачи, а детализацию выдавать в нужном пользователю объёме, а не в максимально возможном объёме.

Также KISS имеет много общего c принципом разделения интерфейса из пяти принципов SOLID, сформулированных Робертом Мартином.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
120
Q

Принцип YAGNI

A

«Вам это не понадобится»
Если упрощенно, то следование данному принципу заключается в том, что возможности, которые не описаны в требованиях к системе, просто не должны реализовываться. Это позволяет вести разработку, руководствуясь экономическими критериями — Заказчик не должен оплачивать ненужные ему функции, а разработчики не должны тратить своё оплачиваемое время на реализацию того, что не требуется.
Основная проблема, которую решает принцип YAGNI — это устранение тяги программистов к излишней абстракции, к экспериментам «из интереса» и к реализации функционала, который сейчас не нужен, но, по мнению разработчика, может либо вскоре понадобиться, либо просто будет полезен, хотя в реальности такого очень часто не происходит.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
121
Q

Принцип SOLID

A

SOLID — это аббревиатура пяти основных принципов проектирования в объектно-ориентированном программировании —
Single responsibility — принцип единственной ответственности
Open-closed — принцип открытости / закрытости
Liskov substitution — принцип подстановки Барбары Лисков
Interface segregation — принцип разделения интерфейса
Dependency inversion — принцип инверсии зависимостей
Принцип единственной обязанности / ответственности (single responsibility principle / SRP) обозначает, что каждый объект должен иметь одну обязанность и эта обязанность должна быть полностью инкапсулирована в класс. Все его сервисы должны быть направлены исключительно на обеспечение этой обязанности. Подробнее про SRP…

Принцип открытости / закрытости (open-closed principle / OCP) декларирует, что программные сущности (классы, модули, функции и т. п.) должны быть открыты для расширения, но закрыты для изменения. Это означает, что эти сущности могут менять свое поведение без изменения их исходного кода. Подробнее про OCP…

Принцип подстановки Барбары Лисков (Liskov substitution principle / LSP) в формулировке Роберта Мартина: «функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа не зная об этом». Подробнее про LSP…

Принцип разделения интерфейса (interface segregation principle / ISP) в формулировке Роберта Мартина: «клиенты не должны зависеть от методов, которые они не используют». Принцип разделения интерфейсов говорит о том, что слишком «толстые» интерфейсы необходимо разделять на более маленькие и специфические, чтобы клиенты маленьких интерфейсов знали только о методах, которые необходимы им в работе. В итоге, при изменении метода интерфейса не должны меняться клиенты, которые этот метод не используют. Подробнее про ISP…

Принцип инверсии зависимостей (dependency inversion principle / DIP) — модули верхних уровней не должны зависеть от модулей нижних уровней, а оба типа модулей должны зависеть от абстракций; сами абстракции не должны зависеть от деталей, а вот детали должны зависеть от абстракций. Подробнее про DIP…

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
122
Q

Пройти циклом по ключам объекта

A
  1. Использование цикла for..in:

const obj = {a: 1, b: 2, c: 3}; for (let key in obj) { console.log(key); // Выводит каждый ключ объекта console.log(obj[key]); // Выводит значение для каждого ключа }

  1. Использование метода Object.keys():

const obj = {a: 1, b: 2, c: 3}; Object.keys(obj).forEach(key => { console.log(key); // Выводит каждый ключ объекта console.log(obj[key]); // Выводит значение для каждого ключа });

  1. Использование метода Object.getOwnPropertyNames():

const obj = {a: 1, b: 2, c: 3}; Object.getOwnPropertyNames(obj).forEach(key => { console.log(key); // Выводит каждый ключ объекта console.log(obj[key]); // Выводит значение для каждого ключа });

  1. Использование метода Object.entries() вместе с циклом for..of:

const obj = {a: 1, b: 2, c: 3}; for (let [key, value] of Object.entries(obj)) { console.log(key); // Выводит каждый ключ объекта console.log(value); // Выводит значение для каждого ключа }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
123
Q

Что такое промис?

A

Promise (обещание) (resolve, reject)

Промис (Promise) — специальный объект JavaScript, который используется для написания и обработки асинхронного кода. Асинхронные функции возвращают объект Promise в качестве значения. Промисы были придуманы для решения проблемы так называемого «ада функций обратного вызова».
Промис может находиться в одном из трёх состояний:
1. pending (в ожидании) — стартовое состояние, операция стартовала;
2.
- fulfilled (выполнено) — получен результат;
или
- rejected (отклонено) — ошибка.
Поменять состояние можно только один раз: перейти из pending либо в fulfilled, либо в rejected.

В качестве параметров конструктор промиса принимает resolve и reject. В resolve записывается результат выполнения операции, в - reject — причина невыполнения операции. Результат может быть обработан в методе .then, ошибка — в методе .catch. Метод then() используют, чтобы выполнить код после успешного выполнения асинхронной операции. Метод .then также возвращает промис, поэтому мы можем использовать цепочку, состоящую из нескольких .then. Метод catch() используют,
чтобы выполнить код в случае ошибки при выполнении асинхронной операции. Метод finally() используют, чтобы выполнить код при завершении асинхронной
операции. Он будет выполнен вне зависимости от того, была ли операция успешной или завершилась ошибкой.

Синтаксис создания Promise:

var promise = new Promise(function(resolve, reject) {
// Эта функция будет вызвана автоматически

// В ней можно делать любые асинхронные операции,
// А когда они завершатся — нужно вызвать одно из:
// resolve(результат) при успешном выполнении
// reject(ошибка) при ошибке
})
Универсальный метод для навешивания обработчиков:

promise.then(onFulfilled, onRejected)
onFulfilled – функция, которая будет вызвана с результатом при resolve.
onRejected – функция, которая будет вызвана с ошибкой при reject.

С помощью методов then(), catch() и finally() мы можем реагировать на изменение состояния промиса и выполнять код.

// Создаётся объект promise let promise = new Promise((resolve, reject) => { setTimeout(() => { // переведёт промис в состояние fulfilled с результатом "result" resolve("result"); }, 1000); }); // // promise.then навешивает обработчики на успешный результат или ошибку promise.then( (result) => { // первая функция-обработчик - запустится при вызове resolve alert("Fulfilled: " + result); // result - аргумент resolve }, (error) => { // вторая функция - запустится при вызове reject alert("Rejected: " + error); // error - аргумент reject } );

Promise.all — это промис, который принимает массив промисов в качестве входных данных (итерируемый), и он разрешается, когда все промисы разрешаются или любое из них отклоняется. Например, синтаксис метода promise.all приведен ниже:
Promise.all([Promise1, Promise2, Promise3]) .then(result) => { console.log(result) }) .catch(error => console.log(Error in promises ${error}))

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
124
Q

Псевдомассивы

A

Array-likes

Псевдомассивы - это объекты, у которых есть индексы и length.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
125
Q

Разница между slice и splice

A

Array.splice («splice» — «наращивать, сращивать») принимает начальный (позицию) и необязательный конечный (количество элементов) аргументы и изменяет содержимое массива, удаляя существующие элементы и/или добавляя новые. Возвращается массив, содержащий удалённые элементы. Если будет удалён только один элемент, вернётся массив из одного элемента. Если никакие элементы не будут удалены, вернётся пустой массив. Используется для вставки или удаления элементов в/из массива.
var x = [14, 3, 77]; var y = x.splice(1, 2); console.log(x); // [14] console.log(y); // [3, 77]

Array.slice (срез) принимает два аргумента, начальный и необязательный конечный. Далее он возвращает новый массив, содержащий элементы начиная с указанного начального индекса вплоть до элемента, расположенного сразу перед конечным индексом. Если вы опустите второй аргумент, он будет выбран до конца. Он не изменяет исходный массив. Используется для выбора элементов из массива
var x = [14, 3, 77]; var y = x.slice(1, 2); console.log(x); // [14, 3, 77] console.log(y); // [3]

Общий пример:
[14, 3, 77].slice(1, 2) // [3] [14, 3, 77].splice(1, 2) // [3, 77]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
126
Q

Разница между scope и context

A

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

Область действия : в JavaScript область действия достигается за счет использования функций. Когда вы используете ключевое слово «var» внутри функции, инициализируемая вами переменная является частной и не может быть видна за пределами этой функции. Но если внутри этой функции есть функции, то эти «внутренние» функции могут «видеть» эту переменную; говорят, что эта переменная находится в области видимости. Функции могут «видеть» переменные, объявленные внутри них. Они также могут «видеть» все, что объявлено вне их, но никогда не могут видеть те, которые объявлены внутри функций, вложенных в эту функцию. Это область видимости в JavaScript.

Контекст : относится к объекту, в котором выполняется функция. Когда вы используете ключевое слово JavaScript «this», это слово относится к объекту, в котором выполняется функция.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
127
Q

Разница между window и document

A

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

window объект представляет текущее окно браузера и предоставляет доступ к различным свойствам и методам, таким как открытие и закрытие окон, установка таймеров, управление размерами и положением окна, обращение к URL-адресу текущей страницы и многое другое. Он также является глобальным объектом JavaScript в браузере, что означает, что его свойства и методы могут быть доступны из любого места в JavaScript-коде.

document объект представляет текущий HTML-документ, загруженный в окне браузера, и предоставляет доступ к различным методам и свойствам, связанным с документом. Например, через document вы можете получить доступ и изменять содержимое документа, создавать новые элементы, добавлять обработчики событий, изменять стили элементов и многое другое. Он также является частью DOM (Document Object Model), который представляет структуру и содержимое HTML-документа в виде дерева объектов, к которым можно обращаться и изменять.

Вкратце говоря, window отвечает за окно браузера и его функциональности, в то время как document относится к HTML-документу, его структуре и возможности работы с ним.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
128
Q

Разница между функцией и методом

A

Разница между функцией и методом заключается в их контексте и способе вызова.

Функция - это совокупность инструкций, которая выполняет определенную операцию или вычисление. Функции могут быть определены независимо от объектов и вызываться в любом месте кода. Они могут принимать аргументы и возвращать значения. Пример:

function greet(name) { console.log(Hello, ${name}!); } greet('John'); // Output: Hello, John!

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

const person = { name: 'John', greet: function() { console.log(Hello, ${this.name}!); } }; person.greet(); // Output: Hello, John!

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
129
Q

Разница циклов for of и for in

A

Оператор for…of выполняет цикл обхода итерируемых объектов (включая Array, Map, Set, объект аргументов и подобных), вызывая на каждом шаге итерации операторы для каждого значения из различных свойств объекта for … of цикл работает только с повторяемыми объектами. В JavaScript итерируемые объекты - это объекты, которые можно перебирать. String, Array, TypedArray, Map и Set - все это встроенные итерируемые объекты, поскольку каждый из их объектов-прототипов реализует метод @@iterator.

Цикл for…in проходит через перечисляемые свойства объекта. Он пройдёт по каждому отдельному элементу.
for … in работает с теми свойствами, у которых enumerable flag установлен в true:
Перечислимый флаг для свойств, созданных с помощью простого присваивания или инициализатора свойств, по умолчанию равен true.
Перечислимый флаг для свойств, созданных с помощью Object.defineProperty, по умолчанию равен false.
Также работает со строками и массивами, поскольку перечислимый флаг для свойств строки и массива также по умолчанию имеет значение true.
Итого:
for…of - Используется для перебора строк и массивов.
for…in - Используйте для перебора объектов.
От себя добавлю, что for…of поставляется с ES2015 и в настоящее время является лучшей практикой (по моему опыту) потому что:
Более читаемый,
Без обратных вызовов,
Быстрее (если верить тестам),
Вы также можете использовать .entries() и деструктурирование.

130
Q

Распространение событий

A

Когда мы нажимаем на какой-либо элемент на станице и генерируется событие нажатия, то это событие может распространяться от элемента к элементу. Например, если мы нажимаем на блок div, то также мы нажимаем и на элемент body, в котором блок div находится. То есть происходит распространение события.

Есть несколько форм распространения событий:

Восходящие: событие распространяется вверх по дереву DOM от дочерних узлов к родительским.
Если такое поведение является нежелаемым, мы можем остановить распространение событие с помощью метода stopPropagation() объекта Event:
var redRect = document.getElementById(“redRect”);
redRect.addEventListener(“click”, function(e){
console.log(“Событие на redRect”);
e.stopPropagation();
});
внутренний элемент (кликнутый) - > его родитель -> родитель родителя … -> body

Нисходящие: событие распространяется вниз по дереву DOM от родительских узлов к дочерним, пока не достигнет того элемента, на котором это событие и возникло. Для их использования в метод addEventListener() в качестве третьего необязательного параметра передается логическое значение true или false, которое указывает, будет ли событие нисходящим. По умолчанию все события восходящие.
body -> родитель элемента -> внутренний элемент (кликнутый)

131
Q

Рекурсия

A

Recursion

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

function factorial(n) { // Если мы пытаемся найти факториал 1, возвращаем 1 — это базовый случай. if (n <= 1) { return 1 } // В остальных случаях возвращаем произведение n на факториал предыдущего числа — таким образом мы от n дойдём до 1, перебрав каждое число. return n * factorial(n - 1) } console.log(factorial(5)) // 120

Рекурсивные структуры данных:
Дерево — это структура, в которой у каждого узла может быть несколько дочерних подузлов — «детей».

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

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

132
Q

Сustom sorting for Array

A

Метод sort() сортирует элементы массива на месте и возвращает ссылку на тот же массив, теперь отсортированный. Порядок сортировки по умолчанию — восходящий, основанный на
преобразовании элементов в строки и последующем сравнении их последовательностей значений кодовых единиц UTF-16.
sort((a, b) => { /* … */ } )

// Compare function sort(compareFn) // Inline compare function sort(function compareFn(a, b) { /* … */ })

compareFn Задает функцию, определяющую порядок сортировки. Если он опущен, элементы массива преобразуются в строки, а затем сортируются в соответствии со значением кодовой
точки Unicode для каждого символа.
Метод sort() возвращает ссылку на исходный массив, поэтому изменение возвращаемого массива также приведет к изменению исходного массива.

133
Q

Самовызывающаяся функция

A

IIFE - Immediately Invoked Function Expression (немедленно вызываемое функциональное выражение). Этот подход позволяет:

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

(function() { // код IIFE })();

  1. С использованием группирующих операторов:

( function() { // код IIFE }());

  1. С использованием оператора вспомогательного знака:

!function() { // код IIFE }();

  1. С использованием оператора минуса:

-var myNamespace = function() { // код IIFE }();

  1. С использованием оператора побитового НЕ:

~function() { // код IIFE }();

134
Q

Свойство Prototype

A

В JavaScript объекты имеют специальное скрытое свойство [[Prototype]] (так оно названо в спецификации), которое либо равно null, либо ссылается на другой объект. Этот объект называется «прототип». Когда мы хотим прочитать свойство из object, а оно отсутствует, JavaScript автоматически берёт его из прототипа. В программировании такой механизм называется «прототипным наследованием».

Свойство [[Prototype]] является внутренним и скрытым, но есть много способов задать его.

  1. Через proto (плохой вариант):
    rabbit.\_\_proto\_\_ = animal;

Есть только два ограничения:

  • Ссылки не могут идти по кругу. JavaScript выдаст ошибку, если мы попытаемся назначить proto по кругу.
  • Значение proto может быть объектом или null. Другие типы игнорируются.
  • Может быть только один [[Prototype]]. Объект не может наследоваться от двух других объектов.
  1. Современные методы:
  • Object.create(proto, [descriptors]) – создаёт пустой объект со свойством [[Prototype]], указанным как proto, и необязательными дескрипторами свойств descriptors.
  • Object.getPrototypeOf(obj) – возвращает свойство [[Prototype]] объекта obj.
  • Object.setPrototypeOf(obj, proto) – устанавливает свойство [[Prototype]] объекта obj как proto.

let animal = {
eats: true
};
// создаём новый объект с прототипом animal
let rabbit = Object.create(animal);
alert(rabbit.eats); // true
// получаем прототип объекта rabbit
alert(Object.getPrototypeOf(rabbit) === animal);
// заменяем прототип объекта rabbit на {}
Object.setPrototypeOf(rabbit, {});

В JavaScript все объекты имеют скрытое свойство [[Prototype]], которое является либо другим объектом, либо null. Мы можем использовать obj.\_\_proto\_\_ для доступа к нему (исторически обусловленный геттер/сеттер, есть другие способы, которые скоро будут рассмотрены). Объект, на который ссылается [[Prototype]], называется «прототипом». Если мы хотим прочитать свойство obj или вызвать метод, которого не существует у obj, тогда JavaScript попытается найти его в прототипе. Операции записи/удаления работают непосредственно с объектом, они не используют прототип (если это обычное свойство, а не сеттер). Если мы вызываем obj.method(), а метод при этом взят из прототипа, то this всё равно ссылается на obj. Таким образом, методы всегда работают с текущим объектом, даже если они наследуются.

Цикл for..in перебирает как свои, так и унаследованные свойства. Остальные методы получения ключей/значений работают только с собственными свойствами объекта. Все встроенные объекты следуют одному шаблону: Методы хранятся в прототипах (Array.prototype, Object.prototype, Date.prototype и т.д.). Сами объекты хранят только данные (элементы массивов, свойства объектов, даты). Примитивы также хранят свои методы в прототипах объектов-обёрток: Number.prototype, String.prototype, Boolean.prototype. Только у значений undefined и null нет объектов-обёрток. Встроенные прототипы могут быть изменены или дополнены новыми методами. Но не рекомендуется менять их. Единственная допустимая причина – это добавление нового метода из стандарта, который ещё не поддерживается движком JavaScript.

Мы можем создавать объекты без прототипов с помощью Object.create(null). Такие объекты можно использовать как “чистые словари”, у них нет проблем с использованием строки “__proto__” в качестве ключа. Ещё методы:

  • Object.keys(obj) / Object.values(obj) / Object.entries(obj) – возвращают массив всех перечисляемых собственных строковых ключей/значений/пар ключ-значение.
  • Object.getOwnPropertySymbols(obj) – возвращает массив всех собственных символьных ключей.
  • Object.getOwnPropertyNames(obj) – возвращает массив всех собственных строковых ключей.
  • Reflect.ownKeys(obj) – возвращает массив всех собственных ключей.
  • obj.hasOwnProperty(key) – возвращает true, если у obj есть собственное (не унаследованное) свойство с именем key.
135
Q

Свойство объекта

A

Object property

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

136
Q

Событийный цикл

A

Поток выполнения в браузере, равно как и в Node.js, основан на событийном цикле. Понимание работы событийного цикла важно для оптимизаций, иногда для правильной архитектуры. В этой главе мы сначала разберём теорию, а затем рассмотрим её практическое применение.

Идея событийного цикла очень проста. Есть бесконечный цикл, в котором движок JavaScript ожидает задачи, исполняет их и снова ожидает появления новых. Общий алгоритм движка:

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

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

Примеры задач:
Когда загружается внешний скрипт

, то задача – это выполнение этого скрипта.
Когда пользователь двигает мышь, задача – сгенерировать событие mousemove и выполнить его обработчики.
Когда истечёт таймер, установленный с помощью setTimeout(func, ...), задача – это выполнение функции func
И так далее.
Задачи поступают на выполнение – движок выполняет их – затем ожидает новые задачи (во время ожидания практически не нагружая процессор компьютера)
Может так случиться, что задача поступает, когда движок занят чем-то другим, тогда она ставится в очередь.
Очередь, которую формируют такие задачи, называют «очередью макрозадач» (macrotask queue, термин v8).
Например, когда движок занят выполнением скрипта, пользователь может передвинуть мышь, тем самым вызвав появление события mousemove, или может истечь таймер, установленный setTimeout, и т.п. Эти задачи формируют очередь, как показано на иллюстрации выше.
Задачи из очереди исполняются по правилу «первым пришёл – первым ушёл». Когда браузер заканчивает выполнение скрипта, он обрабатывает событие mousemove, затем выполняет обработчик, заданный setTimeout, и так далее.
Пока что всё просто, не правда ли?

Отметим две детали:
- Рендеринг (отрисовка страницы) никогда не происходит во время выполнения задачи движком. Не имеет значения, сколь долго выполняется задача. Изменения в DOM отрисовываются только после того, как задача выполнена.
- Если задача выполняется очень долго, то браузер не может выполнять другие задачи, обрабатывать пользовательские события, поэтому спустя некоторое время браузер предлагает «убить» долго выполняющуюся задачу. Такое возможно, когда в скрипте много сложных вычислений или ошибка, ведущая к бесконечному циклу.

Помимо макрозадач, описанных в этой части, существуют микрозадачи, упомянутые в главе Микрозадачи.
Микрозадачи приходят только из кода. Обычно они создаются промисами: выполнение обработчика .then/catch/finally становится микрозадачей. Микрозадачи также используются «под капотом» await, т.к. это форма обработки промиса.
Также есть специальная функция queueMicrotask(func), которая помещает func в очередь микрозадач.
Сразу после каждой макрозадачи движок исполняет все задачи из очереди микрозадач перед тем, как выполнить следующую макрозадачу или отобразить изменения на странице, или сделать что-то ещё.
Например:
setTimeout(() => alert("timeout")); Promise.resolve() .then(() => alert("promise")); alert("code");
Какой здесь будет порядок?

code появляется первым, т.к. это обычный синхронный вызов.
promise появляется вторым, потому что .then проходит через очередь микрозадач и выполняется после текущего синхронного кода.
timeout появляется последним, потому что это макрозадача.
Более подробное изображение событийного цикла выглядит так:
Все микрозадачи завершаются до обработки каких-либо событий или рендеринга, или перехода к другой макрозадаче.
Это важно, так как гарантирует, что общее окружение остаётся одним и тем же между микрозадачами – не изменены координаты мыши, не получены новые данные по сети и т.п.
Если мы хотим запустить функцию асинхронно (после текущего кода), но до отображения изменений и до новых событий, то можем запланировать это через queueMicrotask.

137
Q

Список (связный список) (Структуры данных)

A

Linked Lists
Связный список – это последовательность отдельных узлов, каждый из которых содержит данные, а также ссылку на следующий узел. Таким образом, все узлы последовательно связаны друг с другом. По итогу список выглядит, как вложенные друг в друга объекты.
У каждого узла есть value (значение этого элемента(узла)) и nextNode (ссылка на следующий элемент связного списка).
Оптимален для вставки и удаления (т.к. надо просто “перекинуть” указатель с определенного элемента на следующий).
Плох для индексирования и поиска (сложно получить элемент по его номеру или просто найти элемент из-за вложенности).

Основные операции:
prepend – добавление нового элемента в начало списка;
append – добавление нового элемента в конец списка;
delete – удаление всех элементов с указанным значением.

Дополнительно:
Существует двусвязный список: он имеет помимо nextNode и value ещё и previousNode (значение узла, ссылка на следующий узел и на предыдущий соответственно).

class LinkedListNode { constructor(value, next = null) { this.value = value; this.next = next; } } // class LinkedList { constructor(comparator) { this.head = null; this.tail = null; // this.comparator = comparator || function (i, j) { if (i < j) return -1; if (i > j) return 1; return 0; }; } // prepend(value) { let newNode = new LinkedListNode(value, this.head); this.head = newNode; // if (!this.tail) this.tail = newNode; } // append(value) { let newNode = new LinkedListNode(value); if (this.tail) this.tail.next = newNode; this.tail = newNode; if (!this.head) this.head = newNode; } // delete(value) { if (!this.head) return; // // если удаляется голова списка, // нужно обозначить новую голову while (this.head && this.comparator(this.head.value, value) === 0) { this.head = this.head.next; } // let current = this.head; // if (current !== null) { while (current.next) { if (this.comparator(current.next.value, value) === 0) { current.next = current.next.next; } else { current = current.next; } } } // if (this.comparator(this.tail.value, value) === 0) { this.tail = current; } } }

138
Q

Способы создания объектов в JavaScript

A
  1. const object = new Object(); // конструктор объекта

2.1. const object = Object.create(); // статический метод Object.create() создает новый объект, используя существующий объект в качестве прототипа вновь созданного объекта.
const person = Object.create(
{},
{
name: {
value: “Asya”, // эти поля не будут итерируемыми
},
birthyear: {
value: 1991, // эти поля не будут итерируемыми
}
}
)
2.2. Статический метод Object.assign(целевой объект, изначальный объект, объекты) копирует все перечисляемые собственные свойства из одного или нескольких исходных объектов в целевой объект. Создает независимый клон объекта
const target = {};
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target ); // { b: 4, c: 5 };
target ! == source

3.1. const object = {name: “Umair”, age: 22 }; // литерал объекта

3.2. Спред оператор создает независимый клон объекта
const user = {
name: “Oleg”,
}
const Petya = {…user}

3.3. Глубокое копирование, независимый клон объекта
const user = {
name: “Oleg”,
}
const newObj = Json.parse(JSON.stringify(user))

  1. function Person(name) {
    this.name = name;
    this.age = 22;
    }
    const object = new Person(“Umair”);
  2. function Person() {}
    Person.prototype.name = “Umair”;
    const object = new Person();
    или
    function func {};
    new func(x, y, z);
  3. class Person {
    constructor(name) {
    this.name = name;
    } }
    const object = new Person(“Umair”);
  4. var object = new (function () {
    this.name = “Umair”;
    })();
139
Q

Способы перебора массива

A

forEach – для перебора массива. forEach предназначен для перебора всех элементов массива, но кроме него ES5 предлагает еще несколько полезных методов для перебора всех или некоторых элементов плюс выполнения при этом каких-либо действий с ними:
every — возвращает true, если для каждого элемента массива колбек возвращает значение приводимое к true
some — возвращает true, если хотя бы для одного элемента массива колбек возвращает значение приводимое к true.
filter — создает новый массив, включающий те элементы исходного массива, для которых колбек возвращает true.
map — создает новый массив, состоящий из значений возращаемых колбеком.
reduce — сводит массив к единственному значению, применяя колбек по очереди к каждому элементу массива, начиная с первого (может быть полезен для вычисления суммы элементов массива и других итоговых функций).
reduceRight — работает аналогично reduce, но перебирает элементы в обратном порядке.
Цикл for
Цикл for of
Одним из самых старых способов перебора элементов массива является цикл for по цифровым индексам:
let arr = [“Яблоко”, “Апельсин”, “Груша”];

for (let i = 0; i < arr.length; i++) {
alert( arr[i] );
}
Но для массивов возможен и другой вариант цикла, for..of:
let fruits = [“Яблоко”, “Апельсин”, “Слива”];

// проходит по значениям
for (let fruit of fruits) {
alert( fruit );
}
Цикл for..of не предоставляет доступа к номеру текущего элемента, только к его значению, но в большинстве случаев этого достаточно. А также это короче.
Технически, так как массив является объектом, можно использовать и вариант for..in:
let arr = [“Яблоко”, “Апельсин”, “Груша”];

for (let key in arr) {
alert( arr[key] ); // Яблоко, Апельсин, Груша
}

Но на самом деле это – плохая идея. Существуют скрытые недостатки этого способа:
Цикл for..in выполняет перебор всех свойств объекта, а не только цифровых.
В браузере и других программных средах также существуют так называемые «псевдомассивы» – объекты, которые выглядят, как массив. То есть, у них есть свойство length и индексы, но они также могут иметь дополнительные нечисловые свойства и методы, которые нам обычно не нужны. Тем не менее, цикл for..in выведет и их. Поэтому, если нам приходится иметь дело с объектами, похожими на массив, такие «лишние» свойства могут стать проблемой.
Цикл for..in оптимизирован под произвольные объекты, не массивы, и поэтому в 10-100 раз медленнее. Увеличение скорости выполнения может иметь значение только при возникновении узких мест. Но мы всё же должны представлять разницу.

140
Q

Сравнить 2 объекта

A

С помощью JSON.stringify

const object1 = { title: "Title", id: 1 }; // const object2 = { title: "Title", id: 1 }; console.log(JSON.stringify(object1) === JSON.stringify(object2)); // true

Однако у этого метода есть некоторые ограничения. Например, если свойства объектов идут не в одном порядке, то сравнение вернёт false.

Или сделать свою функцию

function isEqual(object1, object2) { const props1 = Object.getOwnPropertyNames(object1); const props2 = Object.getOwnPropertyNames(object2); // if (props1.length !== props2.length) { return false; } // for (let i = 0; i < props1.length; i += 1) { const prop = props1[i]; const bothAreObjects = typeof(object1[prop]) === 'object' && typeof(object2[prop]) === 'object'; // if ((!bothAreObjects && (object1[prop] !== object2[prop])) || (bothAreObjects && !isEqual(object1[prop], object2[prop]))) { return false; } } // return true; }

141
Q

Стек (Структуры данных)

A

Stack
Обычно реализуется с помощью связного списка, может быть создан и из массива
Стеки — это LIFO-структуры данных (last in, first out).
Аналог стека — стопка тарелок: последнюю добавленную в стопку тарелку возьмут первой.
Head– единственное место для вставки и удаления элементов.

Основные операции:
добавление нового элемента (push);
удаление головного элемента (pop);
чтение головного элемента без удаления (peek).

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

class Stack { top = null; // push(value) { this.top = { prev: this.top, value }; return this; } // pop() { if (!this.top) { return null; } // const value = this.top.value; this.top = this.top.prev; return value; } }

142
Q

Тернарный оператор

A

Используется для определения переменной в зависимости от условия. Его называют «тернарный», так как этот оператор, единственный в своём роде, имеет три аргумента.
Оператор представлен знаком вопроса ?.
let result = условие ? значение1 : значение2;
Сначала вычисляется условие: если оно истинно, тогда возвращается значение1, в противном случае – значение2.
Важно: если не идет присвоения результата тернарного оператора в результат переменной, то лучше использовать if else. Смысл оператора «вопросительный знак» ? – вернуть то или иное значение, в зависимости от условия.

143
Q

Типы свойств объекта

A

Есть два типа свойств объекта.
- Первый тип это свойства-данные (data properties)
- свойства-аксессоры (accessor properties). По своей сути это функции, которые используются для присвоения и получения значения, но во внешнем коде они выглядят как обычные свойства объекта.
Свойства-аксессоры представлены методами: «геттер» – для чтения и «сеттер» – для записи. При литеральном объявлении объекта они обозначаются get (получить) и set (установить)

144
Q

Типы событий JavaScript

A
  1. События пользовательского интерфейса
    Это происходит в результате любого взаимодействия с окном браузера, а не со страницей HTML. В этих событиях мы присоединяем прослушиватель событий к объекту окна, а не к объекту документа. Ниже перечислены различные события пользовательского интерфейса.
    load Событие загрузки срабатывает, когда веб-страница завершает загрузку. Он также может срабатывать на узлах таких элементов, как изображения, сценарии или объекты.
    unload Это событие срабатывает до того, как пользователи покинут страницу, т. е. веб-страница выгружается. Выгрузка страницы обычно происходит из-за того, что была запрошена новая страница.
    error Это событие срабатывает, когда браузер обнаруживает ошибку JavaScript или ресурс, которого не существует.
    resize Он срабатывает, когда мы изменяем размер окна браузера. Но браузеры постоянно запускают это событие, поэтому избегайте использования этого события для запуска сложного кода; это может сделать страницу менее отзывчивой.
    scroll Это событие срабатывает, когда пользователь прокручивает вверх/вниз окно браузера. Он может относиться ко всей странице или к определенному элементу на странице.
  2. Фокус
    Эти события срабатывают, когда элементы HTML, с которыми вы можете взаимодействовать, получают или теряют фокус. Они чаще всего используются в формах и особенно полезны, когда вы хотите выполнить следующие задачи: Для отображения советов или отзывов пользователям при их взаимодействии с элементом в форме. Подсказки обычно отображаются в элементах, отличных от того, с которым взаимодействует пользователь. Чтобы инициировать проверку формы, когда пользователь переходит от одного элемента управления к другому, не дожидаясь отправки формы.
    focus Это событие срабатывает для определенного узла DOM, когда элемент получает фокус.
    blur Это срабатывает для определенного узла DOM, когда элемент теряет фокус
    focusin Это событие совпадает с событием фокуса.
    focusout Это то же событие, что и событие размытия.
  3. События мыши
    Эти события срабатывают, когда мышь перемещается или пользователь нажимает кнопку. Все элементы страницы поддерживают эти события и используют всплывающий подход. Эти действия работают по-разному на устройствах с сенсорным экраном. Предотвращение поведения событий мыши по умолчанию может привести к неожиданным результатам.
    click Это событие срабатывает, когда пользователь нажимает основную кнопку мыши (обычно левую). Это событие также срабатывает, если пользователь нажимает клавишу Enter на клавиатуре, когда элемент находится в фокусе. Сенсорный экран: прикосновение к экрану действует как одиночный щелчок левой кнопкой мыши.
    dblclick Это событие срабатывает, когда пользователь быстро дважды щелкает основную кнопку мыши. Сенсорный экран: двойное нажатие на экран действует как двойной щелчок левой кнопкой мыши. Доступность: Вы можете добавить два вышеуказанных события к любому элементу, но лучше применять их только к элементам, которые обычно нажимаются, иначе они не будут доступны через навигацию с помощью клавиатуры. Все события мыши, обсуждаемые ниже, не могут быть вызваны клавиатурой.
    mousedown Он срабатывает, когда пользователь нажимает любую кнопку мыши. Сенсорный экран: вы можете использовать событие touchstart.
    mouseup Он срабатывает, когда пользователь отпускает кнопку мыши. Сенсорный экран: вы можете использовать событие touchend
    mouseover Он срабатывает, когда пользователь перемещает курсор, который до этого находился вне элемента, внутрь элемента. Можно сказать, что он срабатывает, когда мы наводим курсор на элемент.
    mouseout Он срабатывает, когда пользователь перемещает курсор, который до этого находился внутри элемента, за пределы элемента. Можно сказать, что он срабатывает, когда курсор перемещается за пределы элемента. События mouseover и mouseout обычно изменяют внешний вид графики на нашей веб-странице. Предпочтительной альтернативой этому является использование псевдокласса CSS: hover.
    mousemove Он срабатывает, когда пользователь перемещает курсор вокруг элемента. Это событие часто вызывается.
  4. События клавиатуры
    Эти события запускаются на любом устройстве, когда пользователь взаимодействует с клавиатурой.
    input Это событие срабатывает при изменении значения <input></input> или <textarea> (не срабатывает при удалении в IE9). Вы можете использовать keydown в качестве запасного варианта в старых браузерах.
    keydown Он срабатывает, когда пользователь нажимает любую клавишу на клавиатуре. Если пользователь удерживает клавишу, это событие срабатывает повторно.
    keypress Он срабатывает, когда пользователь нажимает клавишу, что приводит к печати символа на экране. Это событие повторяется, если пользователь удерживает клавишу. Это событие не будет срабатывать для клавиш ввода, табуляции или клавиш со стрелками; событие keydown будет.
    keyup Событие keyup срабатывает, когда пользователь отпускает клавишу на клавиатуре.
    События keydown и keypress срабатывают до появления символа на экране, keyup срабатывает после его отображения.
    Чтобы узнать, какая клавиша нажата при использовании событий keydown и keypress, объект события имеет свойство keyCode . Это свойство вместо того, чтобы возвращать букву для этой клавиши, возвращает ASCII-код нижнего регистра для этой клавиши.</textarea>
  5. Форма событий
    Эти события распространены при использовании форм на веб-странице. В частности, мы видим событие отправки в основном в форме проверки (проверки значений формы). Как описано в нашем руководстве; Особенности JavaScript : если пользователи пропускают какую-либо необходимую информацию или вводят неправильный ввод, проверка перед отправкой данных на сервер выполняется быстрее. В приведенном ниже списке объясняются различные формы событий, доступных пользователю.
    submit Это событие запускается на узле, представляющем элемент <form>, когда пользователь отправляет форму.
    change Он срабатывает при изменении состояния различных элементов формы. Это лучший вариант, чем использование события щелчка, поскольку щелчок — не единственный способ взаимодействия пользователей с формой.
    input Событие ввода очень часто встречается с элементами <input></input> и <textarea>.
    Мы часто используем события focus и blur с формами, но они также доступны в сочетании с другими элементами, такими как ссылки.</textarea>
  6. Мутационные события и наблюдатели
    Всякий раз, когда структура дерева DOM изменяется, это вызывает событие мутации . Изменение в дереве может быть связано с добавлением или удалением узла DOM с помощью вашего скрипта. Но у них есть альтернатива, которая их заменит: наблюдатели за мутациями . Ниже приведены многочисленные события мутации в JavaScript.
    DOMNodeInserted Он срабатывает, когда скрипт вставляет новый узел в дерево DOM с помощью appendChild(), replaceChild(), insertBefore() и т. д.
    DOMNodeRemoved Это событие срабатывает, когда скрипт удаляет существующий узел из дерева с помощью removeChild(), replaceChild() и т. д.
    DOMSubtreeModified Он срабатывает, когда изменяется структура дерева DOM, т. е. происходят два вышеуказанных события.
    DOMNodeInsertedIntoDocument Это событие срабатывает, когда скрипт вставляет узел в дерево DOM в качестве потомка другого узла, уже находящегося в документе.
    DOMNodeRemovedFromDocument Это событие срабатывает, когда скрипт удаляет узел из дерева DOM как потомок другого узла, уже находящегося в документе.
    Проблема с событиями мутации заключается в том, что большое количество изменений на вашей странице может сделать вашу страницу медленной или не отвечающей на запросы. Они также могут запускать другие прослушиватели событий, изменяя DOM и приводя к срабатыванию большего количества событий мутации. Это причина введения в скрипт наблюдателей за мутациями.
    Наблюдатели мутаций ждут, пока сценарий завершит свою текущую задачу, прежде чем реагировать, а затем сообщают об изменениях в пакете (не по одному за раз). Это уменьшает количество событий, возникающих при изменении дерева DOM с помощью сценария. Вы также можете указать, на какие изменения в DOM вы хотите, чтобы они реагировали.
  7. События HTML5
    Это события уровня страницы, включенные в версии специализации HTML5. Новые события поддерживают более современные устройства, такие как телефоны и планшеты. Они реагируют на такие события, как жесты и движения. Вы поймете их лучше после того, как освоите приведенные выше концепции, поэтому сейчас они не обсуждаются. Пока работайте с событиями, указанными ниже, и когда вы станете лучшим разработчиком, вы сможете искать другие доступные события. Три события HTML5, которые мы изучим, следующие:
    DOMContentLoaded Это событие срабатывает, когда формируется дерево DOM, т.е. загружается скрипт. Скрипты начинают выполняться до загрузки всех ресурсов, таких как изображения, CSS и JavaScript . Вы можете прикрепить это событие либо к окну, либо к объектам документа .
    hashchange Он срабатывает, когда хэш URL-адреса изменяется без обновления всего окна. Хэши (#) связывают определенные части (известные как якоря) внутри страницы. Он работает с объектом окна; объект события содержит как свойства oldURL, так и свойства newURL, содержащие URL-адреса до и после изменения хэша.
    beforeunload Это событие срабатывает для объекта окна непосредственно перед выгрузкой страницы. Это событие должно быть полезным для пользователя, а не побуждать его оставаться на странице. Вы можете добавить к событию диалоговое окно, показывающее сообщение, предупреждающее пользователей о том, что их изменения не сохранены.
  8. CSS-события
    Эти события запускаются, когда скрипт встречает элемент CSS. Поскольку CSS является важной частью веб-разработки, разработчики решили добавить эти события в js, чтобы упростить работу с CSS. Вот некоторые из наиболее распространенных событий CSS:
    transitionend Это событие срабатывает, когда в программе завершается переход CSS. Полезно уведомить скрипт об окончании перехода, чтобы он мог предпринять дальнейшие действия.
    animationstart Эти события срабатывают, когда в программе запускается анимация CSS.
    animationiteration Это событие происходит, когда любая анимация CSS повторяется. С помощью этого события мы можем определить, сколько раз анимация повторяется в скрипте.
    animationend Он срабатывает, когда в программе заканчивается анимация CSS. Это полезно, когда мы хотим действовать сразу после завершения процесса анимации.
145
Q

Удалить элемент из конца массива

A

Array.prototype.pop()

146
Q

Удалить элемент из начала массива

A

Array.prototype.shift()

147
Q

Умные параметры функций в деструктуризации

A

Есть ситуации, когда функция имеет много параметров, большинство из которых не обязательны. Это особенно верно для пользовательских интерфейсов. Представьте себе функцию, которая создаёт меню. Она может иметь ширину, высоту, заголовок, список элементов и так далее.
Вот так – плохой способ писать подобные функции:
function showMenu(title = “Untitled”, width = 200, height = 100, items = []) {
// …
}
В реальной жизни проблема заключается в том, как запомнить порядок всех аргументов. Обычно IDE пытаются помочь нам, особенно если код хорошо документирован, но всё же… Другая проблема заключается в том, как вызвать функцию, когда большинство параметров передавать не надо, и значения по умолчанию вполне подходят.
Разве что вот так?
// undefined там, где подходят значения по умолчанию
showMenu(“My Menu”, undefined, undefined, [“Item1”, “Item2”])
Это выглядит ужасно. И становится нечитаемым, когда мы имеем дело с большим количеством параметров.
На помощь приходит деструктуризация!
Мы можем передать параметры как объект, и функция немедленно деструктурирует его в переменные:
// мы передаём объект в функцию
let options = {
title: “My menu”,
items: [“Item1”, “Item2”]
};

// …и она немедленно извлекает свойства в переменные
function showMenu({title = “Untitled”, width = 200, height = 100, items = []}) {
// title, items – взято из options,
// width, height – используются значения по умолчанию
alert( ${title} ${width} ${height} ); // My Menu 200 100
alert( items ); // Item1, Item2
}

showMenu(options);
Мы также можем использовать более сложное деструктурирование с вложенными объектами и двоеточием:
let options = {
title: “My menu”,
items: [“Item1”, “Item2”]
};

function showMenu({
title = “Untitled”,
width: w = 100, // width присваиваем в w
height: h = 200, // height присваиваем в h
items: [item1, item2] // первый элемент items присваивается в item1, второй в item2
}) {
alert( ${title} ${w} ${h} ); // My Menu 100 200
alert( item1 ); // Item1
alert( item2 ); // Item2
}

showMenu(options);
Полный синтаксис – такой же, как для деструктурирующего присваивания:
function({
incomingProperty: varName = defaultValue

})
Тогда для объекта с параметрами будет создана переменная varName для свойства с именем incomingProperty по умолчанию равная defaultValue.
Пожалуйста, обратите внимание, что такое деструктурирование подразумевает, что в showMenu() будет обязательно передан аргумент. Если нам нужны все значения по умолчанию, то нам следует передать пустой объект:
showMenu({}); // ок, все значения - по умолчанию

showMenu(); // так была бы ошибка
Мы можем исправить это, сделав {} значением по умолчанию для всего объекта параметров:
function showMenu({ title = “Menu”, width = 100, height = 200 } = {}) {
alert( ${title} ${width} ${height} );
}

showMenu(); // Menu 100 200
В приведённом выше коде весь объект аргументов по умолчанию равен {}, поэтому всегда есть что-то, что можно деструктурировать.

148
Q

Условный оператор if, if else, switch

A

Иногда нам нужно выполнить различные действия в зависимости от условий.
Инструкция if(…) вычисляет условие в скобках и, если результат true, то выполняет блок кода. Инструкция if (…) вычисляет выражение в скобках и преобразует результат к логическому типу. Если нужно проверить несколько условий используется блок else if. Инструкция if может содержать необязательный блок «else» («иначе»). Он выполняется, когда условие ложно.
Тернарный оператор или «условный» оператор «вопросительный знак». Используются при присвоении или при возврате значения
let result = условие ? значение1 : значение2;
Конструкция switch заменяет собой сразу несколько if. Она представляет собой более наглядный способ сравнить выражение сразу с несколькими вариантами.
switch(x) { // проверяем x с value
case ‘value1’:

[break] // Если break нет, то выполнение пойдёт ниже по следующим case, при этом остальные проверки игнорируются.
case ‘value2’:

[break]
default: // если ни один case не совпал – выполняется (если есть) вариант default.

[break]
}

149
Q

Утиная типизация

A

duck typing
Альтернативный подход к типу – «утиная типизация», которая основана на одной известной пословице: «Если это выглядит как утка, плавает как утка и крякает как утка, то, вероятно, это утка (какая разница, что это на самом деле)»

Смысл утиной типизации – в проверке необходимых методов и свойств.

Например, мы можем проверить, что объект – массив, не вызывая Array.isArray, а просто уточнив наличие важного для нас метода, например splice.

if (something.splice) {
alert( ‘Это утка! То есть, массив!’ );
}

if (x.getTime) {
alert( ‘Дата!’ );
alert( x.getTime() ); // работаем с датой
}

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

Интересно: Если говорить словами «классического программирования», то «duck typing» – это проверка реализации объектом требуемого интерфейса. Если реализует – ок, используем его. Если нет – значит это что-то другое.

150
Q

Флаги и дескрипторы

A

Свойства объекта имеют три специальных атрибута (так называемые «флаги»).
writable – если true, свойство можно изменить, иначе оно только для чтения. Никто не сможет изменить имя пользователя, если только не обновит соответствующий флаг новым вызовом defineProperty.
enumerable – если true, свойство перечисляется в циклах, в противном случае циклы его игнорируют. Используется, если мы хотим, чтобы свойство не попадало в цикл. Но важно помнить, что неперечислимые свойства также не возвращаются Object.keys
configurable – если true, свойство можно удалить, а эти атрибуты можно изменять, иначе этого делать нельзя. Определение свойства как неконфигурируемого – это дорога в один конец. Мы не можем изменить его обратно с помощью defineProperty. Обратите внимание: configurable: false не даст изменить флаги свойства, а также не даст его удалить. При этом можно изменить значение свойства.
Когда мы создаём свойство «обычным способом», все они имеют значение true.
Метод Object.getOwnPropertyDescriptor позволяет получить полную информацию о свойстве. Возвращаемое значение – это объект, так называемый «дескриптор свойства»: он содержит значение свойства и все его флаги.
let descriptor = Object.getOwnPropertyDescriptor(user: obj, ‘name’: descriptorName);
alert( JSON.stringify(descriptor, null, 2 ) );
// дескриптор свойства:
{
“value”: “John”,
“writable”: true,
“enumerable”: true,
“configurable”: true
}

Чтобы изменить флаги, мы можем использовать метод Object.defineProperty. Если свойство существует, defineProperty обновит его флаги. В противном случае метод создаёт новое свойство с указанным значением и флагами; если какой-либо флаг не указан явно, ему присваивается значение false.
let user = {};
Object.defineProperty(user: obj, “name”: descriptorName, { value: “John” }: descriptor);
// выдаст
“value”: “John”,
“writable”: false,
“enumerable”: false,
“configurable”: false

Существует метод Object.defineProperties(obj, descriptors), который позволяет определять множество свойств сразу.
Object.defineProperties(user, {
name: { value: “John”, writable: false },
surname: { value: “Smith”, writable: false },
// …
});

Чтобы получить все дескрипторы свойств сразу, можно воспользоваться методом Object.getOwnPropertyDescriptors(obj).
Вместе с Object.defineProperties этот метод можно использовать для клонирования объекта вместе с его флагами:
let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
Обычно при клонировании объекта мы используем присваивание, чтобы скопировать его свойства:
for (let key in user) {
clone[key] = user[key]
}
…Но это не копирует флаги. Так что если нам нужен клон «получше», предпочтительнее использовать Object.defineProperties.
Другое отличие в том, что for..in игнорирует символьные и неперечислимые свойства, а Object.getOwnPropertyDescriptors
возвращает дескрипторы всех свойств.

Метод Object.create() позволяет создавать новые объекты и соединять их с прототипами существующих объектов.
Метод Object.keys() создает массив ключей объекта.
Метод Object.values() создает массив значений объекта.
Метод Object.entries() создает вложенный массив пар «ключ-значение» объекта.
Метод Object.assign() копирует значения из одного объекта в другой.
Метод Object.freeze() предотвращает модификацию свойств и значений объекта и добавление или удаление свойств объекта.
Метод Object.isFrozen() позволяет определить, был ли объект заморожен или нет, и возвращает логическое значение.
Метод Object.seal()предотвращает добавление новых свойств объекта, но позволяет изменять существующие свойства. Этот метод похож на Object.freeze().
Метод Object.getPrototypeOf() используется для получения внутреннего скрытого [[Prototype]] объекта, также доступного через свойство __proto__.
fromEntries() Создает новый объект из массива пар ключ-значение, переданного в качестве аргумента. Возвращает новый объект.

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

Object.preventExtensions(obj)

Запрещает добавлять новые свойства в
объект.

Object.seal(obj)

Запрещает добавлять/удалять свойства.
Устанавливает configurable: false для
всех существующих свойств.

Object.freeze(obj)

Запрещает добавлять/удалять/изменять
свойства. Устанавливает configurable: false, writable: false для
всех существующих свойств.

А
также есть методы для их проверки:

Object.isExtensible(obj)

Возвращает false,
если добавление свойств запрещено, иначе true.

Object.isSealed(obj)

Возвращает true,
если добавление/удаление свойств запрещено и для всех существующих свойств
установлено configurable: false.

Object.isFrozen(obj)

Возвращает true,
если добавление/удаление/изменение свойств запрещено, и для всех текущих
свойств установлено configurable: false, writable: false.

151
Q

Функции высшего порядка

A

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

function higherOrderFunction(param, callback) { return callback(param) }

152
Q

Функциональное программирование

A

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

Основы:
- Неизменность (Неизменность (Immutability) заключается не в изменении состояния, а в копировании старого состояния, изменении новой копии и замене старого состояния новым.)
- Идемпотентность (Идемпотентность (Idempotent) - означает предсказуемость, т.е. при одном и том же вводном значении, функция всегда должна возвращать один и тот же результат.)
- Императивный и декларативный (Императивный код - это код, который сообщает компьютеру, что и как делать. Компьютеры хороши с императивными инструкциями. Декларативный код - это код, который сообщает компьютеру, что делать и что должно происходить; он не говорит машине, как именно это сделать. Люди хороши в декларативных инструкциях)
- Каррирование (Карринг (curry) - преобразует функцию с несколькими аргументами в серию функций, каждая из которых принимает один аргумент.)
- Частичное применение (Частичное применение (partial application) похоже на карринг - это процесс создания функции с меньшим количеством параметров.)
- Запоминание (Запоминание (memoization) - особый вид кеширования. Он кеширует возвращаемое значение на основе своих параметров. Таким образом, если параметры совпадают, вместо поиска функции и повторного вычисления возвращаемого значения, выполняется поиск значения. Это может сэкономить ценные вычислительные циклы.)
- Чистые функции (чистые функции всегда должны возвращать один и тот же вывод при одинаковом вводе)
- Ссылочная прозрачность (Ссылочная прозрачность (referential transparency) - обычно определяется как факт, что выражение в программе может быть заменено его значением (или чем-либо, имеющим то же значение) без изменения результата программы. Это подразумевает, что методы всегда должны возвращать одно и то же значение для данного аргумента, не оказывая никакого другого влияния.)
- Композиция (Композиция - создание сложной функциональности за счет объединения более простых функций)

Плюсы функционального программирования
- Надёжность и удобство тестирования
- Оптимизация при компиляции
- Параллелизм и потокобезопасность

Минусы функционального программирования
- Повышенное потребление памяти
- Сложность при работе с нечистыми сервисами

153
Q

Функция

A

Function
Функция - это управляемый событиями исполняющий блок кода, который используется многократно.

Функцию можно использовать так же, как и другие типы данных: сохранять в переменную, передавать аргументом и возвращать из функции.
Технически, функция — это объект JavaScript, у которого есть внутренний метод Call(), который добавляет возможность вызова функции.
Передаваемые значения копируются в параметры функции и становятся локальными переменными.
Функции имеют доступ к внешним переменным. Но это работает только изнутри наружу. Код вне функции не имеет доступа к её локальным переменным.
Функция может возвращать значение. Если этого не происходит, тогда результат равен undefined.
Для того, чтобы сделать код более чистым и понятным, рекомендуется использовать локальные переменные и параметры функций, не пользоваться внешними переменными.
Функция, которая получает параметры, работает с ними и затем возвращает результат, гораздо понятнее функции, вызываемой без параметров, но изменяющей внешние переменные, что чревато побочными эффектами.

154
Q

Как называется функция, которая передаётся в качестве аргумента другой функции для последующего её вызова ?

A

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

function callbackFunction(name) { console.log("Hello " + name); } // function outerFunction(callback) { let name = prompt("Please enter your name."); callback(name); } outerFunction(callbackFunction);

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

Хорошей аналогией callback является следующая ситуация: Вы звоните кому-то, он не отвечает, Вы оставляете ему сообщение и ждете, когда он перезвонит. Звонок или сообщение — это событие или данные, а callback — это ожидание (предвосхищение) встречного звонка.

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

async1(function(){ async2(function(){ async3(function(){ async4(function(){ .... }); }); }); });

155
Q

Функция замены гласных в строке

A

str.replace(/[aeiou]/gi, ‘’);

156
Q

Функция-предикат

A

Predicate function

Функция-предикат (функция-вопрос) - это функция, которая возвращает true или false в зависимости от преданного значения.

157
Q

Функция: Вам дан массив. Завершите функцию, которая возвращает количество ВСЕХ элементов в массиве, включая любые вложенные массивы. [1, 2, [3, 4, [5]]] –> 7

A

function deepCount(a){ return a.reduce((acc, val) => { return acc + (Array.isArray(val) ? deepCount(val) : 0); }, a.length); }

или

function countElements(arr) { let flatArr = arr.flat(Infinity); // разглаживаем вложенные массивы return flatArr.length; // возвращаем количество элементов в разглаженном массиве } let arr = [1, 2, [3, 4, [5]]]; console.log(countElements(arr)); // 7

158
Q

Функция: Вам предоставляется словарь/хэш/объект, содержащий несколько языков и результаты вашего теста на данных языках. Верните список языков, на которых ваш тестовый балл не ниже 60, в порядке убывания баллов. {“Java”: 10, “Ruby”: 80, “Python”: 65} –> [“Ruby”, “Python”]

A

function myLanguages(results) { let final = []; let resultArr = Object.entries(results).sort(([,a],[,b]) => b - a); // получаем ключи и значения объекта и соритруем от большего к меньшему [ [ 'Ruby', 80 ], [ 'Python', 65 ], [ 'Java', 10 ] ] resultArr.forEach((key)=>{ if (key[1] >= 60){ //проверяем что значение выше 60 final.push(key[0]); } }) return final; }

159
Q

Функция: Числа Фибоначчи (строка Фибоначчи) — числовая последовательность, первые два числа которой являются 0 и 1, а каждое последующее за ними число является суммой двух предыдущих.

A

function nthFibo(n) { if (n === 1) { return 0; } else if (n === 2) { return 1; } else { return nthFibo(n - 1) + nthFibo(n - 2); } }

160
Q

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

A

function getParticipants(handshakes){ let minPeople = 0 while(handshakes > 0){ handshakes = handshakes - minPeople minPeople++ } return minPeople }

161
Q

Функция: посчитать все пятницы 13 в году

A

function unluckyDays(year){ let unluckyDay = 0; // счетчик for (let i = 0; i < 12; i++){ // проходим по всем месяцам if (new Date(year, i, 13).getDay() === 5){ // получает дату в формате 2792-03-13T00:00:00.000Z и проверяем, что это пятница unluckyDay = unluckyDay + 1; } } return unluckyDay; }

162
Q

Функция: сумма каррирования calculate(2,4)(3,7,1) // should return 17

A

let calculate = (...args1) => (...args2)=> { // получаем первые и вторые аргументы через спред оператор let array = [...args1, ...args2]; // собираем в единый массив return array.reduce((prev, val) => prev + val); // проходимся редьюсом с суммированием и возвращаем результат }

163
Q

Функция: узнать есть ли повторы букв в строке

A

function isIsogram(str){ return new Set(str.toUpperCase()).size == str.length; }

164
Q

Хэш-таблица (Структуры данных)

A

Хэш-таблица
Данные хранятся в виде пар ключ-значение.
Оптимальны для поиска, вставки и удаления.
Эффективность:
Индексирование: O(1).
Поиск: O(1).
Вставка: O(1).

Хеш-таблица — это структура данных, которая строится по принципу ключ-значение. Из-за высокой скорости поиска значений по ключам, она используется в таких структурах, как Map, Dictionary и Object. Как показано на рисунке, хеш-таблица имеет hash function, преобразующую ключи в список номеров, которые используются как имена (значения) ключей. Время поиска значения по ключу может достигать O(1). Одинаковые ключи должны возвращать одинаковые значения — в этом суть функции хэширования.

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

Основные операции:
add: добавить пару ключ/значение
remove: удалить пару
lookup: найти значение по ключу

Интересно: Хеш-таблицы широко используются в программировании, например, для механизмов авторизации, индексации больших объемов информации (баз данных), кеширования или поиска, а также в криптографии для шифрования информации.

165
Q

Цепочка прототипов

A

prototype chain
В плане наследования JavaScript работает лишь с одной сущностью: объектами. Каждый объект имеет внутреннюю ссылку на другой объект, называемый его прототипом. У объекта-прототипа также есть свой собственный прототип и так далее до тех пор, пока цепочка не завершится объектом, у которого свойство prototype равно null. null, по определению, не имеет прототипа и служит в качестве завершающего звена в цепочке прототипов.
Object.create() и class являются способами создания цепочки прототипов.
Прототип экземпляра объекта доступен через Object.getPrototypeOf(object) или свойство proto, тогда как прототип функции конструктора доступен через Object.prototype.

166
Q

Цикл

A

Loop
Цикл— это повторяющаяся последовательность действий. Цикл состоит из условия и тела цикла. Перед запуском цикла проверяется условие. Если условие истинное, то выполняется блок кода, который называется телом цикла. Затем этот шаг повторяется. Так будет продолжаться, пока условие не станет ложным. Каждое выполнение тела цикла называется итерацией.

Тело цикла — это набор инструкций, заключённый в фигурные скобки. Одно выполнение тела называют итерацией цикла.

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

Внутри цикла можно использовать оператор break, он прерывает цикл. break стараются не использовать, потому что он ведёт себя как второе условие цикла и понижает читаемость. Почти всегда цикл с break можно переписать без этого оператора, изменив условие или добавив дополнительную проверку.

Внутри цикла можно использовать оператор continue, он прерывает текущую итерацию и возвращается к проверке условия. Оператор стараются не использовать, потому что он усложняет чтение кода — появляется ещё одно место, где итерация может завершиться. Почти всегда цикл с continue можно переписать на цикл без него, добавив ветвление if
Цикл for

  1. Инициализация — в этой части задаётся начальное значение счётчика цикла.
  2. Условие — тут задаётся условие по которому выполняется цикл. Если условие ложно, работа цикла прекращается и тело цикла не выполняется.
  3. Завершающая операция — в этой части задаётся выражение, которое будет исполнено после выполнения тела цикла. Обычно здесь содержится выражение изменения счётчика.
  4. Тело цикла — это блок операций, которые будут выполнены в случае если условие истинно.

while – Проверяет условие перед каждой итерацией.

let i = 0; while (i < 3) { // выводит 0, затем 1, затем 2 alert( i ); i++; }

do..while – Проверяет условие после каждой итерации.

let i = 0; do { alert( i ); i++; } while (i < 3);

for (;;) – Проверяет условие перед каждой итерацией, есть возможность задать дополнительные настройки.

for (let i = 0; i < 3; i++) { // выведет 0, затем 1, затем 2 alert(i); }

Чтобы организовать бесконечный цикл, используют конструкцию while (true). При этом он, как и любой другой цикл, может быть прерван директивой break.
Если на данной итерации цикла делать больше ничего не надо, но полностью прекращать цикл не следует – используют директиву continue.
Обе этих директивы поддерживают метки, которые ставятся перед циклом. Метки – единственный способ для break/continue выйти за пределы текущего цикла, повлиять на выполнение внешнего.

167
Q

Чистая функция

A

Чистая функция (Pure function (determenistic algorithm)
) — это функция, которая не вызывает побочных эффектов (side effects), то есть никак не влияет на состояние внешнего мира. Чистая функция возвращает идентичный результат для одинаковых переданных аргументов, а также не имеет побочных эффектов.

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

Например, pureFn() при вводе 10 и 20 всегда будет возвращать 15, значит она чистая:

function pureFn(a, b) { return ((a + b) * a) / b }

168
Q

Что такое AJAX?

A

AJAX = Asynchronous Javascript And XML. Это подход к асинхронному (неблокирующему) обмену данными с сервером. AJAX или Asyncronous JavaScript and XML — это набор взаимосвязанных технологий, которые позволяют работать с данными в асинхронном режиме. Это означает, что мы можем отправлять данные на сервер и получать данные с него без перезагрузки веб-страницы.

AJAX использует следующие технологии:
HTML — структура веб-страницы.
CSS — стили веб-страницы.
JavaScript — поведение страницы и работа с DOM.
XMLHttpRequest API — отправка и получение данных с сервера.
PHP, Python, Nodejs — какой-нибудь серверный язык.

169
Q

Что такое DOM?

A

Document Object Model (объектная модель документа) — это прикладной программный интерфейс (API) для работы с HTML и XML документами. Когда браузер первый раз читает («парсит») HTML документ, он формирует большой объект, действительно большой объект, основанный на документе — DOM. DOM представляет собой древовидную структуру (дерево документа). DOM используется для взаимодействия и изменения самой структуры DOM или его отдельных элементов и узлов. В JS DOM представлен объектом Document.

Объект document содержит большое количество свойств и методов, которые позволяют работать с HTML. Дерево состоит из обычных и текстовых узлов. Обычные узлы — это HTML-теги, а текстовые узлы — текст внутри тегов. Обычный узел называется Element, и он содержит в себе описание тега, атрибутов тега и обработчиков.
У любого узла есть один родительский узел и дочерние. Родительский узел — элемент, в который вложен текущий узел, он может быть только один. Дочерние — узлы, которые вложены в текущий узел.
Это правило не работает только в двух случаях:
корневой узел — у такого узла нет родителя;
текстовый узел — у таких узлов нет дочерних узлов, только родитель. Последний уровень любого DOM-дерева состоит из текстовых узлов.

Свойства:
title — заголовок документа. Браузер обычно показывает его на вкладке.
forms — получить список форм на странице. Свойство только для чтения, напрямую перезаписать его нельзя.
body — получить <body> элемент страницы.
head — получить <head> элемент страницы.

Методы:
getElementById — поиск элемента по идентификатору;
getElementsByClassName — поиск элементов по названию класса;
getElementsByTagName — поиск элементов по названию тега;
querySelector — поиск первого элемента, подходящего под CSS-селектор;
querySelectorAll — поиск всех элементов подходящих под CSS-селектор.

170
Q

Что такое ECMAScript?

A

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

171
Q

Что такое JSON?

A

JSON (англ. JavaScript Object Notation) — текстовый формат обмена данными, основанный на JavaScript. Но при этом формат независим от JS и может использоваться в любом языке программирования.

JSON-объект — это неупорядоченное множество пар «ключ: значение». Ключи пишутся в кавычках.
JSON.parse(text) преобразование строки в собственный объект
JSON.stringify(object)преобразование собственного объекта в строку, чтобы его можно было передавать по сети.

172
Q

Что такое Map и в чем отличие от Object?

A

Map – это коллекция ключ/значение, как и Object. Но основное отличие в том, что Map позволяет использовать ключи любого типа. Map даже может использовать объекты в качестве ключей.

Методы и свойства:

new Map() – создаёт коллекцию.
map.set(key, value) – записывает по ключу key значение value.
map.get(key) – возвращает значение по ключу или undefined, если ключ key отсутствует.
map.has(key) – возвращает true, если ключ key присутствует в коллекции, иначе false.
map.delete(key) – удаляет элемент (пару «ключ/значение») по ключу key.
map.clear() – очищает коллекцию от всех элементов.
map.size – возвращает текущее количество элементов
values() — возвращает итератор всех значений коллекции;
keys() — возвращает итератор всех ключей коллекции;
entries() — возвращает итератор пар [ключ, значение];
forEach(колбэк) — перебирает ключи и значения коллекции.
Содержит свойство size для получения количества значений в коллекции.

Для перебора коллекции Map есть 3 метода:

map.keys() – возвращает итерируемый объект по ключам,
map.values() – возвращает итерируемый объект по значениям,
map.entries() – возвращает итерируемый объект по парам вида [ключ, значение], этот вариант используется по умолчанию в for..of.
Кроме этого, Map имеет встроенный метод forEach, схожий со встроенным методом массивов Array.

При создании Map мы можем указать массив (или другой итерируемый объект) с парами ключ-значение для инициализации:
let map = new Map([
[‘1’, ‘str1’],
[1, ‘num1’],
[true, ‘bool1’]
]);
alert( map.get(‘1’) ); // str1

Если у нас уже есть обычный объект, и мы хотели бы создать Map из него, то поможет встроенный метод Object.entries(obj), который получает объект и возвращает массив пар ключ-значение для него, как раз в этом формате.
let obj = {
name: “John”,
age: 30
};
let map = new Map(Object.entries(obj));
alert( map.get(‘name’) ); // John

Есть метод Object.fromEntries, с помощью которого можно из Map сделать объект.

173
Q

Что такое REST API?

A

REST API — это способ взаимодействия сайтов и веб-приложений с сервером. Его также называют RESTful. API (Application Programming Interface) — это код, который позволяет двум приложениям обмениваться данными с сервера. На русском языке его принято называть программным интерфейсом приложения. REST (Representational State Transfer) — это способ создания API с помощью протокола HTTP. На русском его называют «передачей состояния представления».

Технологию REST API применяют везде, где пользователю сайта или веб-приложения нужно предоставить данные с сервера. Например, при нажатии иконки с видео на видеохостинге REST API проводит операции и запускает ролик с сервера в браузере. В настоящее время это самый распространенный способ организации API. Он вытеснил ранее популярные способы SOAP и WSDL.

Принципы :
1. Отделения клиента от сервера (Client-Server). В REST API код запросов остается на стороне клиента, а код для доступа к данным — на стороне сервера.
2. Отсутствие записи состояния клиента (Stateless). Сервер не должен хранить информацию о состоянии (проведенных операций) клиента. Каждый запрос от клиента должен содержать только ту информацию, которая нужна для получения данных от сервера.
3. Кэшируемость (Casheable). В данных запроса должно быть указано, нужно ли кэшировать данные (сохранять в специальном буфере для частых запросов). Если такое указание есть, клиент получит право обращаться к этому буферу при необходимости.
4. Единство интерфейса (Uniform Interface). Все данные должны запрашиваться через один URL-адрес стандартными протоколами, например, HTTP.
5. Многоуровневость системы (Layered System). В RESTful сервера могут располагаться на разных уровнях, при этом каждый сервер взаимодействует только с ближайшими уровнями и не связан запросами с другими.
6. Предоставление кода по запросу (Code on Demand). Серверы могут отправлять клиенту код (например, скрипт для запуска видео). Так общий код приложения или сайта становится сложнее только при необходимости.
7. Начало от нуля (Starting with the Null Style). Клиент знает только одну точку входа на сервер. Дальнейшие возможности по взаимодействию обеспечиваются сервером.

При создании REST API есть общепринятые лучшие практики, например:

  • использование защищенного протокола HTTPS
  • использование инструментов для разработки API Blueprint и Swagger
  • применение приложения для тестирования Get Postman
  • применение как можно большего количества HTTP-кодов (список)
  • архивирование больших блоков данных
174
Q

Что такое SPA и как сделать его SEO-friendly?

A

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

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

Для того, чтобы сделать SPA SEO-friendly, можно обратиться к таким решениям, как предварительный рендеринг или серверный рендеринг.

175
Q

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

A

Classes
Классы — это относительно новый способ написания функций-конструкторов в JS. Это синтаксический сахар для функций-конструкторов. В основе классов лежат те же прототипы и прототипное наследование. JS – это язык, основанный на прототипах, и внутри него классы используются только в качестве синтаксического сахара.

Видеоигры: все персонажи обладают определёнными характеристиками (свойствами) вроде цвета, роста, имени и т.д., а также способностями (методами) вроде прыжка, бега, удара и т.п. Отличным инструментом для хранения всей подобной информации выступают объекты. Создание класса позволяет нам в дальнейшем инстанцировать (создавать) из него объекты, которые будут наследовать все содержащиеся в нём свойства и методы.

`class Person{
constructor(firstName, lastName, age, address){
this.firstName = firstName
this.lastName = lastName
this.age = age
this.address = address
}

static self(){
return this
}

toString(){
return ‘[object Person]’
}

getFullName(){
return ${this.firstName} ${this.lastName}
}
}`

class MyClass {
prop = value; // свойство
constructor(…) { // конструктор
// …
}
method(…) {} // метод
get something(…) {} // геттер
set something(…) {} // сеттер
Symbol.iterator {} // метод с вычисляемым именем (здесь - символом)
// …
}
MyClass технически является функцией (той, которую мы определяем как constructor), в то время как методы, геттеры и сеттеры записываются в MyClass.prototype.

176
Q

Что такое стрелочные функции?

A

Arrow function
Стрелочная функция (иногда называют лямбда-функция) — это более короткий синтаксис функционального выражения и не имеет собственного this, arguments, super или new.target.

177
Q

Что такое цель события или целевой элемент (event.target)?

A

event.target — это элемент, в котором происходит событие, или элемент, вызвавший событие.

Event.currentTarget — это элемент, к которому прикреплен прослушиватель событий.

178
Q

В чем разница между стеком вызовов и очередью задач?

A

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

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

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

179
Q

Что такое API?

A

API (Application Programming Interface) — это набор фич, которые одна программа представляет всем остальным. API может использоваться не только для общения браузера и сервера (через GET и POST запросы), но и в принципе для общения разных программ друг с другом.

Идеальное API:
- Бесшовность (Невозможно написать «универсальный модуль», который бы подошёл к любому проекту. Но зато возможно написать модуль, который бы был достаточно абстрактным. В таком случае, чтобы добавить его в проект, нам потребуется какое-то количество дополнительного кода, но мы сможем использовать уже написанные функции)
- Быстродействие (Чем меньше времени тратится на общение и выполнение нужных действий, тем лучше спроектировано API)
- Понятность (Чем точнее названы функции, методы или ссылки в API, тем меньше заблуждений и ошибок будет возникать при работе с ним)
- Полнота (Чем грамотнее спроектировано API (а скорее даже вся программная система), тем более полным будет ответ на каждое конкретное действие)

Какие API бывают в клиент-серверной архитектуре?
1. REST (Representational State Transfer) — архитектурный стиль общения компонентов, при котором все необходимые данные указываются в параметрах запроса.
Плюсы:
- самый распространённый стиль;
- использует фундаментальную технологию (HTTP), как основу;
- достаточно легко читается.
Минусы:
- если спроектирован плохо, может отправлять или слишком много информации, либо слишком мало. (Но для обхода этой проблемы можно использовать backend for frontend).
2. SOAP (Simple Object Access Protocol) — формат обмена данными.
Это структурированный формат обмена данными, то есть каждое сообщение следует определённой структуре. Чаще всего вместе с SOAP используется XML для отражения этой структуры.
Плюсы:
- не зависит от методов передачи;
- есть структура сообщения.
Минусы
- многословен;
- проигрывает REST в простоте.
3. RPC (Remote Procedure Call) — это такой стиль, при котором в сообщении запроса хранится и действие, которое надо выполнить, и данные, которые для этого действия нужны.
Плюсы:
- есть структура сообщения;
- использует JSON, что делает его проще для чтения и написания;
- производителен, если нужны batch-запросы.
Минусы:
- слишком много логики уходит на клиент;
- HTTP-кэширование недоступно.

180
Q

Что такое arguments?

A

Arguments — это коллекция аргументов, передаваемых функции. arguments — массивоподобный объект, к его элементам можно обращаться по индексу, у него есть свойство length, но arguments не имеет остальных методов массива, таких как push() или filter(). Arguments - это устаревший способ получить все значения, переданные в функцию при вызове. В современном коде рекомендуется использовать остаточные параметры(…).

Преобразовать arguments в массив можно с помощью Array.prototype.slice:

Array.prototype.slice.call(arguments)

Запомните: в стрелочных функциях объект arguments не работает.

Это псевдомассив со всеми аргументами под порядковыми номерами arguments[0]. Перебор через for (let smth of arguments)

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

Rest параметры представляют неизвестное количество аргументов внутри функции, тогда как объект arguments представляет все аргументы, переданные в функцию.

181
Q

Что такое async/await?

A

Async/await — относительно новый способ написания асинхронного (неблокирующего) кода в JS. Им оборачивают промис. Он делает код более читаемым и чистым, чем промисы и функции обратного вызова. Запомните: использование ключевого слова «async» перед функцией заставляет ее возвращать промис.

async function callApi(){
try{
const resp = await fetch(‘url/to/api/endpoint’)
const data = await res.json()
// работаем с данными
} catch(e){
// работаем с ошибкой
}
}

182
Q

Что такое куки?

A

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

Файлы cookie используются для запоминания информации о профиле пользователя (например, имя пользователя). В основном это включает в себя два шага,
Когда пользователь посещает веб-страницу, профиль пользователя может быть сохранен в файле cookie.
Когда пользователь в следующий раз посещает страницу, файл cookie запоминает профиль пользователя.
Для файла cookie доступно несколько следующих вариантов,
По умолчанию файл cookie удаляется при закрытии браузера, но вы можете изменить это поведение, установив дату истечения срока действия (в формате UTC).
document.cookie = “username=John; expires=Sat, 8 Jun 2019 12:00:00 UTC”;
По умолчанию файл cookie принадлежит текущей странице. Но вы можете указать браузеру, к какому пути относится файл cookie, используя параметр пути.
document.cookie = “username=John; path=/services”;
Вы можете удалить файл cookie, установив дату истечения срока действия как прошедшую дату. В этом случае вам не нужно указывать значение cookie. Например, вы можете удалить файл cookie имени пользователя на текущей странице, как показано ниже.
document.cookie =
“username=; expires=Fri, 07 Jun 2019 00:00:00 UTC; path=/;”;

183
Q

Экранирующая последовательность

A

Escape sequence

\n перевод строки
\t табуляция
let str = ‘what' s up? ‘ экранирование кавычек
\ экранирование обратного слеша

184
Q

Элемент в DOM

A

Element

Элемент — это кусочек HTML в DOM-дереве. Браузер создаёт DOM для взаимодействия между JavaScript и HTML. Каждый HTML-тег при этом превращается в элемент DOM. Ещё такие элементы называют узлами. Из DOM можно получить элемент и изменить его. Браузер заметит изменения и отобразит их на странице.
Свойства и методы, связанные с DOM:
children — список дочерних элементов;
parentElement — получить родительский элемент;
nextElementSibling и previousElementSibling — получить следующий/предыдущий узел-сосед:
Свойства с информацией о содержимом:
innerHTML — это свойство возвращает HTML-код всего, что вложено в текущий элемент. При записи в это свойство, предыдущее содержимое будет затёрто. Страница отобразит новое содержимое. Пример: <a>Главная</a>
outerHTML — это свойство возвращает HTML-код текущего элемента и всего, что в него вложено. При записи в это свойство, предыдущее содержимое будет затёрто. Пример: <li id="1" class="menu-item active"><a>Главная</a></li>
textContent — свойство, возвращает текст всех вложенных узлов без HTML-тегов. Пример: Главная
Важно: Если нужно добавить текст в элемент, то всегда используйте свойство textContent. Другие свойства обрабатывают HTML, это может привести к дырам в безопасности.

185
Q

деструктуризация объекта

A

Object Destructuring
Деструктуризация — относительно новый способ получения (извлечения) значений объекта или массива.

Допустим, у нас есть такой объект:

`const employee = {
firstName: ‘Marko’,
lastName: ‘Polo’,
position: ‘Software Developer’,
yearHired: 2017
}

//Синтаксис деструктуризации следующий: заключаем свойства объекта, которые хотим получить, в фигурные скобки ({ }), а если речь идет о массиве — в квадратные скобки ([ ]):
let { firstName, lastName, position, yearHired } = employee

//Для изменения имени переменной следует использовать «propertyName: newName»:
let { firstName: fName, lastName: lName, position, yearHired } = employee

//Для присвоения переменным значения по умолчанию следует использовать «propertyName = ‘defaultValue’»:
let { firstName = ‘Mark’, lastName: lName, position, yearHired } = employee`

186
Q

запоминание или мемоизация

A

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

187
Q

Что такое цикл событий (event loop) и как он работает?

A

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

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

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

Event loop (цикл событий) - это механизм, который позволяет JavaScript обрабатывать события и выполнять асинхронные операции в однопоточной среде. В JavaScript, так как он выполняется в браузере или на сервере, который работает на базе событий, event loop играет ключевую роль в обработке событий и управлении асинхронным кодом.

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

Рабочий принцип event loop следующий:

  1. Глобальная очередь событий (event queue) содержит все глобальные события JavaScript, включая взаимодействие с пользователем, AJAX-запросы, таймеры и другие асинхронные операции.
  2. JavaScript движок, например, V8 (используется в браузерах Chrome и Node.js), работает в одном потоке и постоянно выполняет код из текущей глобальной очереди событий по одному событию за раз.
  3. Когда JavaScript движок встречает асинхронную операцию, такую как AJAX-запрос или таймер, он передает ее на соответствующий механизм браузера или операционной системы и продолжает выполнение остальной части кода без блокировки.
  4. По окончании асинхронной операции, браузер или операционная система помещают соответствующее событие в глобальную очередь событий.
  5. Когда JavaScript движок завершает выполнение текущего кода или приступает к следующему циклу выполнения, он проверяет глобальную очередь событий и обрабатывает следующее доступное событие. Это может быть событие пользовательского взаимодействия, ответ на AJAX-запрос или выполнение таймера.
188
Q

Что такое прототип объекта в JavaScript?

A

Объекты в JavaScript можно организовать в цепочки так, чтобы свойство, не найденное в одном объекте, автоматически искалось бы в другом. Связующим звеном выступает специальное свойство __proto__

Если один объект имеет специальную ссылку __proto__ на другой объект, то при чтении свойства из него, если свойство отсутствует в самом объекте, оно ищется в объекте __proto__. Недостаток этого подхода – он не работает в IE10-.

К счастью, в JavaScript с древнейших времён существует альтернативный, встроенный в язык и полностью кросс-браузерный способ. Чтобы новым объектам автоматически ставить прототип, конструктору ставится свойство prototype.

При создании объекта через new, в его прототип __proto__ записывается ссылка из prototype функции-конструктора.

Значением Person.prototype по умолчанию является объект с единственным свойством constructor, содержащим ссылку на Person.

189
Q

Что такое Set, Map, WeakSet и WeakMap?

A

В ES-2015 появились новые типы коллекций в JavaScript: Set, Map, WeakSet и WeakMap.

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

'use strict'; let map = new Map(); map.set('1', 'str1'); // ключ-строка map.set(1, 'num1'); // число map.set(true, 'bool1'); // булевое значение // в обычном объекте это было бы одно и то же, // map сохраняет тип ключа alert( map.get(1) ); // 'num1' alert( map.get('1') ); // 'str1' alert( map.size ); // 3

Set – коллекция для хранения множества значений, причём каждое значение может встречаться лишь один раз. Например, к нам приходят посетители, и мы хотели бы сохранять всех, кто пришёл. При этом повторные визиты не должны приводить к дубликатам, то есть каждого посетителя нужно «посчитать» ровно один раз. Set для этого отлично подходит:

'use strict'; let set = new Set(); let vasya = {name: "Вася"}; let petya = {name: "Петя"}; let dasha = {name: "Даша"}; // посещения, некоторые пользователи заходят много раз set.add(vasya); set.add(petya); set.add(dasha); set.add(vasya); set.add(petya); // set сохраняет только уникальные значения alert( set.size ); // 3 set.forEach( user => alert(user.name ) ); // Вася, Петя, Даша

WeakSet – особый вид Set, не препятствующий сборщику мусора удалять свои элементы. То же самое – WeakMap для Map. То есть, если некий объект присутствует только в WeakSet/WeakMap – он удаляется из памяти. Это нужно для тех ситуаций, когда основное место для хранения и использования объектов находится где-то в другом месте кода, а здесь мы хотим хранить для них «вспомогательные» данные, существующие лишь пока жив объект. Например, у нас есть элементы на странице или, к примеру, пользователи, и мы хотим хранить для них вспомогательную информацию, например обработчики событий или просто данные, но действительные лишь пока объект, к которому они относятся, существует. Если поместить такие данные в WeakMap, а объект сделать ключом, то они будут автоматически удалены из памяти, когда удалится элемент. Например:

// текущие активные пользователи let activeUsers = [ {name: "Вася"}, {name: "Петя"}, {name: "Маша"} ]; // вспомогательная информация о них, // которая напрямую не входит в объект юзера, // и потому хранится отдельно let weakMap = new WeakMap(); weakMap.set(activeUsers[0], 1); weakMap.set(activeUsers[1], 2); weakMap.set(activeUsers[2], 3); weakMap.set('Katya', 4); //Будет ошибка TypeError: "Katya" is not a non-null object alert( weakMap.get(activeUsers[0]) ); // 1 activeUsers.splice(0, 1); // Вася более не активный пользователь // weakMap теперь содержит только 2 элемента activeUsers.splice(0, 1); // Петя более не активный пользователь // weakMap теперь содержит только 1 элемент

190
Q

Что такое статический метод класса (static)?

A

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

class Repo { static getName() { return "Repo name is modern-js-cheatsheet" } } // // нам не нужно создавать объект класса Repo console.log(Repo.getName()) // "Repo name is modern-js-cheatsheet" // let r = new Repo(); console.log(r.getName()) // необработанная ошибка TypeError: r.getName не является функцией

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

191
Q

Что такое HTTP?

A

Протокол передачи гипертекста (Hypertext Transfer Protocol - HTTP) - это прикладной протокол для передачи гипертекстовых документов, таких как HTML. Он создан для связи между веб-браузерами и веб-серверами, хотя в принципе HTTP может использоваться и для других целей. Протокол следует классической клиент-серверной модели, когда клиент открывает соединение для создания запроса, а затем ждет ответа. HTTP - это протокол без сохранения состояния, то есть сервер не сохраняет никаких данных (состояние) между двумя парами “запрос-ответ”. Несмотря на то, что HTTP основан на TCP/IP, он также может использовать любой другой протокол транспортного уровня с гарантированной доставкой.

Ниже перечислены общие функции, управляемые с HTTP:

Кэш. Сервер может инструктировать прокси и клиенты: что и как долго кэшировать. Клиент может инструктировать прокси промежуточных кэшей игнорировать хранимые документы.
Ослабление ограничений источника. Для предотвращения шпионских и других, нарушающих приватность, вторжений, веб-браузер обчеспечивает строгое разделеление между веб-сайтами. Только страницы из того же источника могут получить доступ к информации на веб-странице. Хотя такие ограничение нагружают сервер, заголовки HTTP могут ослабить строгое разделение на стороне сервера, позволяя документу стать частью информации с различных доменов (по причинам безопасности).
Аутентификация. Некоторые страницы доступны только специальным пользователям. Базовая аутентификация может предоставляться через HTTP, либо через использование заголовка WWW-Authenticate и подобных ему, либо с помощью настройки спецсессии, используя куки.
Прокси и тунелирование. Серверы и/или клиенты часто располагаются в интранете, и скрывают свои истинные IP-адреса от других. HTTP запросы идут через прокси для пересечения этого сетевого барьера. Не все прокси – HTTP прокси. SOCKS-протокол, например, оперирует на более низком уровне. Другие, как, например, ftp, могут быть обработаны этими прокси.
Сессии. Использование HTTP кук позволяет связать запрос с состоянием на сервере. Это создает сессию, хотя ядро HTTP – протокол без состояния. Это полезно не только для корзин в интернет-магазинах, но также для любых сайтов, позволяющих пользователю настроить выход.

192
Q

Из чего состоит HTTP-запрос?

A

Запросы содержат следующие элементы:

HTTP-метод, обычно глагол подобно GET, POST или существительное, как OPTIONS или HEAD, определяющее операцию, которую клиент хочет выполнить. Обычно, клиент хочет получить ресурс (используя GET) или передать значения HTML-формы (используя POST), хотя другие операция могут быть необходимы в других случаях.
Путь к ресурсу: URL ресурсы лишены элементов, которые очевидны из контекста, например без protocol (http://), domain (здесь developer.mozilla.org), или TCP port (здесь 80).
Версию HTTP-протокола.
Заголовки (опционально), предоставляюшие дополнительную информацию для сервера.
Или тело, для некоторых методов, таких как POST, которое содержит отправленный ресурс.

193
Q

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

A

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

GET запрашивает представление ресурса. Запросы с использованием этого метода могут только извлекать данные.
HEAD запрашивает ресурс так же, как и метод GET, но без тела ответа.
POST используется для отправки сущностей к определённому ресурсу. Часто вызывает изменение состояния или какие-то побочные эффекты на сервере.
PUT заменяет все текущие представления ресурса данными запроса.
DELETE удаляет указанный ресурс.
CONNECT устанавливает “туннель” к серверу, определённому по ресурсу.
OPTIONS используется для описания параметров соединения с ресурсом.
TRACE выполняет вызов возвращаемого тестового сообщения с ресурса.
PATCH используется для частичного изменения ресурса.

194
Q

Что такое Cross-Origin Resource Sharing (CORS)?

A

Cross-Origin Resource Sharing (CORS) — механизм, использующий дополнительные HTTP-заголовки, чтобы дать возможность агенту пользователя получать разрешения на доступ к выбранным ресурсам с сервера на источнике (домене), отличном от того, что сайт использует в данный момент. Говорят, что агент пользователя делает запрос с другого источника (cross-origin HTTP request), если источник текущего документа отличается от запрашиваемого ресурса доменом, протоколом или портом.

В целях безопасности браузеры ограничивают cross-origin запросы, инициируемые скриптами. Например, XMLHttpRequest и Fetch API следуют политике одного источника (same-origin policy). Это значит, что web-приложения, использующие такие API, могут запрашивать HTTP-ресурсы только с того домена, с которого были загружены, пока не будут использованы CORS-заголовки.

195
Q

Что такое HTTP cookie и для чего их используют?

A

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

Cookie используются, главным образом, для:

Управления сеансом (логины, корзины для виртуальных покупок)
Персонализации (пользовательские предпочтения)
Мониторинга (отслеживания поведения пользователя)
Получив HTTP-запрос, вместе с откликом сервер может отправить заголовок Set-Cookie с ответом. Cookie обычно запоминаются браузером и посылаются в значении заголовка HTTP Cookie с каждым новым запросом к одному и тому же серверу. Можно задать срок действия cookie, а также срок его жизни, после которого cookie не будет отправляться. Также можно указать ограничения на путь и домен, то есть указать, в течении какого времени и к какому сайту оно отсылается.

Куки можно создавать через JavaScript при помощи свойства Document.cookie. Если флаг HttpOnly не установлен, то и доступ к существующим cookies можно получить через JavaScript.

document.cookie = "yummy_cookie=choco"; document.cookie = "tasty_cookie=strawberry";

196
Q

Что такое Babel и для чего он используется?

A

Babel.JS – это транспайлер, переписывающий код на ES-2015 в код на предыдущем стандарте ES5.

Обычно Babel.JS работает на сервере в составе системы сборки JS-кода (например webpack или brunch) и автоматически переписывает весь код в ES5.

Настройка такой конвертации тривиальна, единственно – нужно поднять саму систему сборки, а добавить к ней Babel легко, плагины есть к любой из них.

Конфигурация Babel прописывается в файле babel.config.js, либо в .babelrc для настроек одного пакета, а также в package.json или .babelrc.js

Пример конфига в babel.config.js:

module.exports = function (api) { api.cache(true); // const presets = [ ... ]; const plugins = [ ... ]; // return { presets, plugins }; }

197
Q

Для чего используется WebSocket? В чем принцип его работы?

A

Протокол WebSocket («веб-сокет»), описанный в спецификации RFC 6455, обеспечивает возможность обмена данными между браузером и сервером через постоянное соединение. Данные передаются по нему в обоих направлениях в виде «пакетов», без разрыва соединения и дополнительных HTTP-запросов.

Чтобы открыть веб-сокет-соединение, нам нужно создать объект new WebSocket, указав в url-адресе специальный протокол ws: let socket = new WebSocket("ws://javascript.info");

Как только объект WebSocket создан, мы должны слушать его события. Их всего 4:

open – соединение установлено,
message – получены данные,
error – ошибка,
close – соединение закрыто.
Вот пример:

let socket = new WebSocket("wss://javascript.info/article/websocket/demo/hello"); // socket.onopen = function(e) { alert("[open] Соединение установлено"); alert("Отправляем данные на сервер"); socket.send("Меня зовут Джон"); }; // socket.onmessage = function(event) { alert([message] Данные получены с сервера: ${event.data}); }; // socket.onclose = function(event) { if (event.wasClean) { alert([close] Соединение закрыто чисто, код=${event.code} причина=${event.reason}); } else { // например, сервер убил процесс или сеть недоступна // обычно в этом случае event.code 1006 alert('[close] Соединение прервано'); } }; // socket.onerror = function(error) { alert([error] ${error.message}); };

Вызов socket.send(body) принимает body в виде строки или любом бинарном формате включая Blob, ArrayBuffer и другие. Дополнительных настроек не требуется, просто отправляем в любом формате. При получении данных, текст всегда поступает в виде строки. А для бинарных данных мы можем выбрать один из двух форматов: Blob или ArrayBuffer.

198
Q

Что такое Веб-компоненты и какие технологии в них используются?

A

Веб-компоненты — технология, которая позволяет создавать многократно используемые компоненты в веб-документах и веб-приложениях. Веб-компоненты поддерживаются веб-браузерами напрямую и не требуют дополнительных библиотек для работы.

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

Custom Elements — API для создания собственных HTML элементов.
HTML Templates — тег позволяет реализовывать изолированные DOM-элементы.
Shadow DOM — изолирует DOM и стили в разных элементах.
HTML Imports — импорт HTML документов.

199
Q

Что такое CORS?

A

CORS (Cross-Origin Resource Sharing) - механизм, который дает возможность клиенту (агенту) получать разрешение на доступ к ресурсам сервера на домене, который отличается о того, который использует сайт. Механизм использует дополнительные HTTP-заголовки. Если источник документа, с которого происходит запрос на ресурс, отличается от ресурса протоколом, доменом или портом, то считается, что агент делает запрос с другого источника. Т.е. происходит cross-origin HTTP request.
Говорят, что агент пользователя делает запрос с другого источника (cross-origin HTTP request), если источник текущего документа отличается от запрашиваемого ресурса доменом, протоколом или портом.

200
Q

Для чего нужен CORS?

A

Браузеры ограничивают запросы с другого источника (cross-origin запросы) в целях безопасности. Такие запросы могут совершать, например, сторонние скрипты, подключенные на сайт. Такие API как Fetch или XMLHttpRequest следуют политике одного источника (same-origin policy). Таким образом, при использовании web-приложением этого API, существует ограничение: домен запрошенных HTTP-ресурсов и домен web-приложения должен быть одним и тем же. Для снятия этого ограничения нужно использовать CORS-заголовки.
Следующие вопросы связаны с работой HTTP протокола. Ответы на эти вопросы важно знать. Крупные компании часто задают эти вопросы на собеседованиях на позицию фронтенд разработчика.

201
Q

Из чего состоит HTTP-запрос?

A

HTTP-метод - глагол (например, GET, POST) или существительное (например, OPTIONS, HEAD), которое определяет действие, которое хочет выполнить клиент.
Путь к ресурсу:
протокол (http://)
домен (example.com)
TCP порт (80)
Версия HTTP-протокола.
Заголовки (опционально). Предоставляют дополнительную информацию для сервера.
Тело запроса (опционально). Некоторые методы (например, POST), могут содержать данные об отправляемом ресурсе.

202
Q

Что такое HTTP cookie?

A

HTTP cookie (куки) - это небольшой фрагмент данных, который отправляется сервером в браузер пользователя. Далее браузер может сохранить cookie и отправлять обратно серверу с каждым запросом. Такой механизм позволяет узнать, с одного и того же браузера были отправлены запросы или нет. Это используется, например, для аутентификации пользователя.
Сам протокол HTTP не хранит состояние, механизм cookie позволяет добавить в него состояние.

Cookie используются, главным образом, для:
Управления сеансом (логины, корзины для виртуальных покупок)
Персонализации (запоминать предпочтения пользователя)
Мониторинга (отслеживания поведения пользователя)
Получив HTTP-запрос, сервер вместе с ответом может отправить заголовок Set-Cookie. Cookie обычно запоминаются браузером и отправляются в HTTP заголовке с каждым последующим запросом к серверу, который сохранил эти cookie.
Cookie можно настраивать, задав срок действия или срок его существования. Также можно указать ограничения на путь и домен. Если флаг HttpOnly не установлен, то доступ к существующим cookies можно получить через JavaScript.

203
Q

Что такое HTTP?

A

Протокол передачи гипертекста (Hypertext Transfer Protocol, HTTP). Это протокол прикладного уровня для передачи гипертекстовых документов, таких как HTML. Он создан для связи между веб-браузерами и веб-серверами.
Протокол следует классической клиент-серверной модели. Клиент открывает соединение для создания запроса, а затем ждет ответа. HTTP - это протокол без сохранения состояния, т.е. сервер не сохраняет никаких данных (состояние) между двумя парами “запрос-ответ”.
Несмотря на то, что HTTP основан на TCP/IP, он также может использовать любой другой протокол транспортного уровня с гарантированной доставкой.

204
Q

Особенности протокола HTTP

A

Простота. HTTP удобен и прост для восприятия человеком. HTTP сообщения легко читать и тестировать.

Расширяемость. За счет HTTP-заголовков можно легко его расширить, добавив новую функциональность на основе соглашений между клиентом и сервером.

Нет состояния, но есть сессия. Между разными запросами не существует связи. Однако, cookie позволяют использовать сессии для идентификации пользователей.

Соединение управляется на транспортном уровне. Протокол требует надёжность и отсутствие потерянных сообщений. Подходящим транспортным протоколом является TCP.

205
Q

Отличия HTTP/1.0, HTTP/1.1, HTTP/2

A

HTTP/1.0 открывал TCP-соединение для каждого обмена запросом/ответом. Открытие соединения требует нескольких обменов сообщениями, и потому это медленный процесс.

HTTP/1.1 предоставил конвейерную обработку (которую оказалось трудно реализовать) и устойчивые соединения: лежащее в основе TCP соединение можно частично контролировать через заголовок Connection.

HTTP/2 добавил мультиплексирование сообщений через простое соединение, помогающее держать соединение теплым и более эффективным.

206
Q

Что такое debounce?

A

debounce() — это функция, которая «откладывает» вызов другой функции до того момента, когда с последнего вызова пройдёт определённое количество времени.

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

Это бывает нужно в не только в формах поиска, как у нас, но и если мы пишем:

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

207
Q

Как проверить, является ли объект массивом?

A

Для этого можно использовать встроенный метод Array.isArray().

208
Q

Объясните разницу между const person = Person() и const person = new Person() при function Person(){}

A

Если функция Person() не возвращает явным образом создаваемый экземпляр, то вариант const person = Person() присвоит константе person значение undefined, поскольку именно таков результат void функции.

Если функция Person явным образом возвращает экземпляр, он станет значением константы person при const person = Person().

Однако, вариант с использование оператора new “выигрывает”, поскольку он устанавливает корректную связь объекта person с цепочкой прототипов Person, в то время как выражение const person = Person() просто присваивает константе результат вызова функции.

209
Q

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

A

Атрибут - это HTML-термин, в то время как свойство - термин из JavaScript. Иными словами, если речь идет о значении в HTML-разметке, мы говорим об атрибуте. Однако, если имеется в виду свойство объекта, к которому мы получили доступ средствами JavaScript - вернее называть это свойством.

210
Q

В чем разница между ES6 class и ES5 function constructor?

A

Классы, добавленные в стандарте EcmaScript 6, всего лишь синтаксический сахар поверх всем известных прототипов.

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

211
Q

Как работает boxing/unboxing в JavaScript?

A

Boxing и unboxing - это процессы автоматического преобразования между примитивными типами данных и их соответствующими объектными представлениями (обертками) в JavaScript.

Boxing - это процесс преобразования примитивного значения в соответствующий объект-обертку этого значения.

Unboxing - это процесс преобразования объектного значения обратно в примитивное значение.

В JavaScript существуют три объектные обертки для примитивных типов данных:

  1. String: Обертка для строковых значений.
  2. Number: Обертка для числовых значений.
  3. Boolean: Обертка для логических (булевых) значений.

Процесс boxing происходит автоматически, когда примитивное значение используется в контексте, где ожидается объект. Например:

let str = "Hello"; let strObject = new String(str); // Boxing console.log(typeof strObject); // object

Процесс unboxing происходит автоматически, когда объект обертки использован, где ожидается примитивное значение. Например:

let num = new Number(42); let unboxedNum = num.valueOf(); // Unboxing using valueOf() method console.log(typeof unboxedNum); // number

212
Q

Почему не стоит использовать конструкторы типа new String?

A

Использование конструкторов типа new String, new Number, new Boolean не рекомендуется по нескольким причинам:

  1. Создание лишних объектов: Когда мы используем конструкторы типа new String, new Number, new Boolean, мы фактически создаем новые объекты обертки вместо примитивных типов данных. При каждом создании такого объекта выделяется память и происходит дополнительная нагрузка на систему. В большинстве случаев, когда просто нужно работать с примитивными значениями, использование объектных оберток нецелесообразно и может вызывать проблемы с производительностью.
  2. Различия в поведении и приведении типов: Объектные обертки ведут себя по-другому, чем соответствующие примитивные типы данных. Например, объект типа String обладает рядом свойств и методов, таких как length или charAt(). Это может приводить к неожиданному поведению в некоторых ситуациях и вызывать сложности с приведением типов. Также, при сравнении объектов оберток и примитивных значений с использованием операторов равенства (== или ===), могут возникать нежелательные результаты из-за разных типов.
  3. Чтение и запись значений: Когда мы используем объектные обертки, чтение и запись значений может быть более сложным и громоздким, по сравнению с работой с примитивными типами данных. Например, при использовании объекта типа String, чтение значения может потребовать вызова метода valueOf(), а запись значения может потребовать вызова метода toString(). Это может затруднить кодирование и сопровождение кода.

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

213
Q

Что такое Garbage Collector? Опишите основные принципы работы «сборщика мусора» в JS-движках (engines).

A

Garbage Collector (сборщик мусора) - это автоматический механизм, используемый в средах выполнения JavaScript (JS-движках), который отслеживает и удаляет неиспользуемые объекты из памяти компьютера. Отсутствие необходимости явно освобождать память вручную является одним из преимуществ использования высокоуровневых языков, таких как JavaScript.

Основные принципы работы «сборщика мусора» в JS-движках:
1. Отслеживание идентифицируемых объектов: Сборщик мусора в JS-движке отслеживает создание и использование объектов во время выполнения программы. Когда создается новый объект, ему выделяется память, и он помечается как “ожидаемый для использования”.

  1. Определение недостижимых объектов: Сборщик мусора в JS-движке проверяет, достижимы ли объекты по отношению к корневым объектам. Корневые объекты - это объекты, которые заранее известны и имеют ссылки на другие объекты в программе (например, глобальные переменные или объекты стека вызовов).
  2. Маркировка доступных объектов: Сборщик мусора проходит по всем объектам, начиная с корневых объектов, и помечает все достижимые объекты, считая их “доступными для использования”. Объекты, которые не были помечены, считаются “недостижимыми” и подлежат очистке из памяти.
  3. Освобождение неиспользуемых объектов: После завершения маркировки, сборщик мусора освобождает память, удаляя объекты, которые не были помечены как “доступные для использования”. Это осуществляется путем освобождения занимаемой ими памяти и восстановления этой памяти для будущего использования.

Процесс сборки мусора самостоятельно выполняется в JS-движках и основан на алгоритмах, таких как “Mark and Sweep” или “Generational Collection”. Эти алгоритмы оптимизируют сборку мусора, чтобы минимизировать влияние на производительность приложения.

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

214
Q

В чем разница между Promise.all () и Promise.allSettled()?

A

Promise.all() и Promise.allSettled() - это два метода, используемые для работы с несколькими промисами в JavaScript, но они имеют разные особенности и возвращают разные результаты:

Promise.all(): Метод Promise.all() принимает массив промисов и возвращает новый промис, который исполняется, когда все промисы в массиве успешно завершены или отклонены. Если хотя бы один из переданных промисов отклонен, возвращаемый промис тоже будет отклонен. Результатом Promise.all() является массив результатов успешно выполненных промисов в том же порядке, в котором они были переданы.

Пример использования Promise.all():

const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]; // Promise.all(promises) .then(result => console.log(result)) // [1, 2, 3] .catch(error => console.log(error));

Promise.allSettled(): Метод Promise.allSettled() принимает массив промисов и возвращает новый промис, который исполняется, когда все промисы из массива завершены (вне зависимости от результата - отклонены или успешно выполнены). Результатом Promise.allSettled() является массив объектов, каждый из которых содержит состояние (fulfilled или rejected) и значение результата или причину отклонения для каждого промиса.

Пример использования Promise.allSettled():

const promises = [Promise.resolve(1), Promise.reject('error'), Promise.resolve(3)]; // Promise.allSettled(promises) .then(result => console.log(result)) /* [ { status: 'fulfilled', value: 1 }, { status: 'rejected', reason: 'error' }, { status: 'fulfilled', value: 3 } ] */ .catch(error => console.log(error));

Таким образом, основная разница между Promise.all() и Promise.allSettled() заключается в том, как они обрабатывают отклоненные промисы. Promise.all() промис будет отклонен сразу же, как только один из промисов в массиве отклонится, в то время как Promise.allSettled() даст возможность промисам завершиться, и затем вернёт результат в виде массива объектов состояний и значений/причин отклонения для каждого промиса.

215
Q

Что такое дескрипторы свойств объектов? Расскажите об их практическом применении.

A

Дескрипторы свойств объектов - это специальные объекты, которые определяют атрибуты и поведение отдельных свойств объекта в JavaScript. Каждое свойство объекта имеет свои собственные дескрипторы, которые могут быть получены и изменены с помощью методов, таких как Object.getOwnPropertyDescriptor(), Object.defineProperty(), Object.defineProperties() и других.

Дескриптор свойства состоит из следующих атрибутов:

  • value: Значение свойства.
  • writable: Указывает, может ли значение свойства быть изменено.
  • enumerable: Указывает, будет ли свойство перечисляемым в цикле for...in или при вызове метода Object.keys().
  • configurable: Указывает, может ли свойство быть удалено или его атрибуты изменены.

Практическое применение дескрипторов свойств объектов включает:

  1. Управление доступом к свойствам: С помощью дескрипторов свойств можно определить, разрешено ли изменять или прочитывать свойство. Например, можно сделать свойство только для чтения, устанавливая значение атрибута writable в false.
  2. Инкапсуляция: Использование дескрипторов свойств позволяет управлять уровнем доступа к свойствам объекта. Можно скрыть определенные свойства от внешнего доступа или определить, что свойство доступно только для чтения.
  3. Валидация значений: Дескрипторы свойств позволяют определить пользовательские функции, которые будут вызываться при установке или получении значения свойства. Это позволяет выполнить валидацию или обработку значений перед их присваиванием или чтением.

Объекты с дескрипторами свойств часто используются для реализации паттернов проектирования, таких как доступ к данным (getters и setters), инкапсуляция и контроль доступа. Они предоставляют разработчикам больше гибкости и контроля над свойствами объектов, что может быть полезно в сложных системах и библиотеках.

216
Q

В чем принципиальная разница между событиями mouseleave и mouseout?

A
  • mouseleave срабатывает только тогда, когда указатель мыши покидает элемент самого элемента, на котором было сгенерировано событие. Оно не срабатывает, когда указатель мыши покидает вложенные элементы. Если указатель мыши входит в дочерний элемент, событие не генерируется для родительского элемента.
  • mouseout срабатывает, когда указатель мыши покидает элемент, на котором было сгенерировано событие, или любой вложенный элемент. Оно срабатывает, когда указатель мыши покидает как сам элемент, так и его дочерние элементы. Если указатель мыши входит в другой элемент внутри текущего элемента, событие генерируется для родительского элемента перед генерацией для вложенного элемента.
217
Q

В каком порядке обрабатываются пользовательские события в DOM (click, mouseover и т.д.)? FIFO или LIFO?

A

Обработка пользовательских событий в DOM происходит в порядке FIFO (First In, First Out) - первым пришел, первым обработан. Это означает, что события обрабатываются в том порядке, в котором они произошли. Если несколько событий происходят одновременно, в разных элементах или на одном и том же элементе, события обрабатываются в порядке, определенном в спецификации DOM.

Например, если пользователь щелкает по элементу A, затем по элементу B и затем снова по элементу A, события клика будут обрабатываться именно в таком порядке: A -> B -> A. Это связано с механизмами обработки и пулом задач (event loop) в браузере, которые обеспечивают правильную последовательность выполнения событий.

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

218
Q

Что такое Event bubbling и Event capturing?

A

Event bubbling (всплытие событий) и event capturing (перехват событий) - это два различных подхода к обработке событий, которые происходят во вложенных элементах в структуре DOM.

Event bubbling (всплытие событий) - это процесс, при котором событие сначала срабатывает на самом вложенном элементе, затем переходит к его родительским элементам вверх по иерархии. Событие, происходящее на дочернем элементе, “всплывает” и передается по цепочке родительских элементов. Всплытие событий продолжается, пока событие не достигнет корневого элемента (обычно `` или document).

Event capturing (перехват событий) - это противоположный процесс, когда событие сначала перехватывается на корневом элементе и затем передается вниз по иерархии к целевому элементу. В перехвате событий событие начинается с корневого элемента и передается на каждом уровне вложенности до достижения целевого элемента.

Оба подхода, всплытие и перехват событий, являются частью механизма распространения событий в DOM. По умолчанию, события в DOM проходят через всплытие, но вы также можете использовать метод addEventListener() с опцией {capture: true} для включения перехвата событий.

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

219
Q

Сравните методы объекта event stopPropagation и stopImmediateProparation.

A

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

  1. stopPropagation(): Метод stopPropagation() прекращает дальнейшее всплытие события или перехват события. Когда вызывается метод stopPropagation(), событие будет остановлено на текущем элементе, и оно не будет передаваться родительским или вложенным элементам.
  2. stopImmediatePropagation(): Метод stopImmediatePropagation() также прекращает дальнейшее всплытие или перехват события, но с одним дополнительным эффектом. Он предотвращает выполнение других обработчиков, прикрепленных к тому же элементу, на котором был вызван stopImmediatePropagation(). Это значит, что даже если существуют другие обработчики для этого события на текущем элементе, они не будут вызваны.

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

220
Q

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

A
  1. Уменьшение размера и количество запросов: Сократите количество и размер загружаемых ресурсов, таких как изображения, стили CSS и скрипты JavaScript. Используйте сжатие (например, Gzip) и оптимизируйте ресурсы, чтобы они были как можно меньше.
  2. Кэширование: Включите кэширование, чтобы браузер мог сохранять копии файлов на стороне клиента и не загружать их снова при повторных запросах.
  3. Асинхронная загрузка: Загружайте ресурсы асинхронно, чтобы они не блокировали основную часть страницы. Используйте атрибуты async и defer для скриптов и стилей.
  4. Минификация и обфускация: Сократите размер JavaScript, CSS и HTML файлов путем удаления ненужных пробелов, комментариев и лишних символов. Также рекомендуется обфусцировать код, чтобы сделать его труднее для чтения и понимания.
  5. Оптимизация изображений: Сжимайте изображения без потери качества и выбирайте наиболее подходящий формат (JPEG, PNG, WebP) для каждого изображения. Используйте CSS спрайты и ленивую загрузку изображений.
  6. Уменьшение количества HTTP запросов: Объединяйте несколько файлов в один, чтобы сократить количество HTTP запросов. Например, объедините несколько CSS файлов или JavaScript файлов в один.
  7. Асинхронная загрузка контента: Загружайте контент по мере его появления на странице, чтобы ускорить начальную загрузку. Используйте техники такие как “ленивая загрузка” (lazy loading), “бесконечная прокрутка” (infinite scrolling) или “постепенная загрузка” (progressive loading).
  8. Оптимизация запросов к серверу: Сократите время обработки сервером, уменьшив объем передаваемых данных и оптимизировав запросы к базе данных или сторонним API.
  9. Оптимизация кода JavaScript: Используйте эффективный и производительный код JavaScript. Пересмотрите и оптимизируйте циклы, избегайте медленных операций (например, частого обращения к DOM), выполняйте асинхронные операции только при необходимости.
  10. Минимальный использование сторонних библиотек: Ограничьте использование сторонних библиотек и плагинов. Используйте только необходимые функции и избегайте тяжелых и медленных библиотек.
  11. Оптимизация критического пути рендеринга: Сделайте критический контент доступным как можно быстрее, чтобы улучшить восприятие времени загрузки страницы. Встроенные стили и скрипты, их минифицирование и асинхронная загрузка могут помочь в ускорении этого процесса.
  12. Использование CDN и архитектурного кэша: Используйте Content Delivery Network (CDN) для доставки статического контента ближе к пользователям и использования архитектурного кэша для улучшения времени отклика сервера.
  13. Профилирование и тестирование производительности: Используйте инструменты для профилирования и тестирования производительности, чтобы выявить проблемные места в коде и оптимизировать их.
221
Q

Web worker-ы. Опишите особенности передачи данных между worker-ми и основным потоком, между разделенными worker-ми.

A

Web Workers - это механизм веб-браузера, который позволяет выполнять скрипты в фоновом потоке, отдельно от основного потока исполнения JavaScript (также известного как поток UI). Это значит, что вы можете выполнять длительные вычисления или операции ввода-вывода в фоновом режиме, не блокируя основной поток и сохраняя отзывчивость пользовательского интерфейса.

Особенности передачи данных между Web Worker и основным потоком:
- Передача данных осуществляется через сериализацию и десериализацию. При отправке данных из основного потока в Web Worker их необходимо сериализовать с использованием стандартных методов связанных с данными, таких как postMessage(). В Web Worker данные десериализуются, чтобы быть использованными.
- Каждый сообщение, отправленное из основного потока в Web Worker, обрабатывается асинхронно. Это означает, что вы не можете быть уверены, в каком порядке сообщения будут обработаны Web Worker’ом.

Особенности передачи данных между разными Web Worker-ами:
- Web Worker’ы не имеют прямого доступа друг к другу, каждый из Worker’ов работает в отдельном изолированном окружении.
- Для обмена данными между различными Web Worker’ами необходимо использовать механизмы, предоставляемые API SharedWorker или WebSocket, которые позволяют обмениваться сообщениями или использовать общие ресурсы, такие как разделяемые массивы (SharedArrayBuffer) или разделяемые буферы (SharedBuffer).

В целом, Web Worker’ы предоставляют механизм для многопоточности в JavaScript, что позволяет выполнять длительные операции без блокировки основного потока и повышает производительность веб-приложений. Однако, взаимодействие и передача данных между различными компонентами Web Worker’ов требует строгого управления и использования соответствующих API и методов.

222
Q

Что такое Transferable-объекты?

A

Transferable objects (передаваемые объекты) - это механизм в JavaScript, который позволяет эффективно передавать большие объемы данных между различными потоками с использованием Web Workers или метода transferrable objects в API postMessage().

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

Важно отметить, что используемые объекты должны быть “передаваемыми” (transferable). Некоторые типы данных, такие как Typed Arrays, ArrayBuffer, MessagePort, ImageBitmap и OffscreenCanvas являются передаваемыми, и их можно безопасно перемещать между потоками. Однако, объекты, которые не являются передаваемыми, будут скопированы вместо перемещения, что может привести к потере производительности.

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

223
Q

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

A
  1. Вертикальное разделение задач (Vertical Splitting): Разделите большие и ресурсоемкие операции на множество меньших частей, чтобы не блокировать основной поток исполнения JavaScript. Можно использовать requestAnimationFrame или Web Workers для разделения задач.
  2. Ленивая загрузка (Lazy Loading): Откладывайте загрузку ресурсоемких операций до тех пор, пока они не понадобятся. Это может включать отложенную загрузку изображений, выполнять вычисления только при прокрутке или при взаимодействии пользователя.
  3. Разделение на фреймы (Frame Slicing): Разделите выполнение ресурсоемких операций на несколько итераций, чтобы не блокировать основной поток. Например, можно использовать setTimeout или requestAnimationFrame внутри цикла для выполнения частей операции поэтапно.
  4. Оптимизация циклов: Избегайте ненужных повторений в циклах и избегайте манипуляций с DOM внутри цикла. Если возможно, используйте более эффективные методы циклов, такие как for-of, for-in, forEach.
  5. Оптимизация работы с DOM: Минимизируйте количество обращений к DOM, так как доступ к нему является дорогостоящей операцией. Вместо этого, кэшируйте ссылки на элементы DOM и выполните все манипуляции с DOM за одно обращение.
  6. Дебаунсинг и Троттлинг: Ограничьте количество вызовов ресурсоемких операций путем использования методов дебаунсинга или троттлинга. Например, можно использовать функции debounce или throttle для ограничения частоты вызовов обработчиков событий.
  7. Кэширование и Мемоизация: Если операции имеют часто повторяющиеся результаты, можно использовать кэширование или мемоизацию, чтобы избежать повторных вычислений. Это особенно полезно для функций с долгим временем выполнения или вычислительно сложных операций.
  8. Использование Web Workers: Выполняйте ресурсоемкие операции в фоновых потоках с использованием Web Workers. Это позволяет выполнять вычисления параллельно, не блокируя основной поток и не ухудшая производительность рендеринга контента.
224
Q

Расскажите, как вы понимаете Web Accessibility.

A

Web Accessibility (Веб-поддержка) - это концепция и практика создания и разработки веб-сайтов и приложений, которые доступны и использовать людям с различными способностями, включая людей с ограниченными возможностями. Цель веб-поддержки включает в себя создание сайтов, которые доступны для всех пользователей, в том числе людей с нарушениями зрения, слуха, мобильности или когнитивными ограничениями. Это включает в себя использование правильной семантики HTML, доступным расширенным инструментам, правильной структуры и улучшенной навигации для помощи пользователям с использованием вспомогательных технологий, таких как считыватели с экрана или команды голосом. Веб-поддержка имеет важное значение для содействия включению и равенству в интернет-пространстве.

225
Q

Разница между циклом событий, микрозадачей и макрозадачей

A

Цикл событий (event loop) - это механизм в JavaScript, который обеспечивает асинхронное выполнение кода и обработку событий. Он работает непрерывно и повторяется, проверяя очередь событий и выполнение задач.

Микрозадача (microtask) - это категория задач, которая выполняется внутри одного цикла событий перед отрисовкой следующего кадра анимации. Микрозадачи могут быть добавлены в очередь с помощью функции Promise.then(), MutationObserver или queueMicrotask(). Они выполняются до того, как браузер обновит пользовательский интерфейс, что позволяет выполнять быстрое и отзывчивое обновление состояния.

Макрозадача (macrotask) - это категория задач, которая также выполняется внутри цикла событий, но после выполнения микрозадач. Макрозадачи включают в себя обработку пользовательских событий, выполнение скриптов, загрузку ресурсов и другие задачи. Примерами макрозадач могут быть функции setTimeout, setInterval, requestAnimationFrame и обработчики событий таких как click и DOMContentLoaded.

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

226
Q

Перспективы и особенности работы с JavaScript

A
  1. Широкая поддержка: JavaScript поддерживается всеми современными браузерами и является основным языком для фронтенд-разработки веб-приложений.
  2. Быстрое развитие: JavaScript постоянно развивается и обновляется с помощью новых стандартов ECMAScript. Это позволяет разработчикам использовать новые функции и возможности языка, улучшая их производительность и эффективность.
  3. Множество фреймворков и библиотек: JavaScript имеет огромное сообщество разработчиков, которое активно разрабатывает фреймворки и библиотеки для упрощения и ускорения разработки. Некоторые популярные фреймворки - Angular, React и Vue.js.
  4. Универсальность: JavaScript можно использовать не только для фронтенда, но и для разработки серверной части (с использованием Node.js), создания мобильных приложений (с помощью React Native), программирования роботов (с использованием библиотеки Johnny-Five) и даже разработки десктопных приложений (с помощью Electron).
  5. Возможности интерактивности: JavaScript позволяет создавать интерактивные и динамические веб-приложения. С помощью JavaScript можно изменять содержимое и стили страницы, обрабатывать события, выполнять валидацию данных и многое другое.
227
Q

Прототипы и наследование прототипов в JavaScript

A

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

  1. Прототип объекта: У каждого объекта в JavaScript есть свойство \_\_proto\_\_, которое ссылается на его прототип. Прототип - это другой объект, который используется для наследования свойств и методов.
  2. Прототипное наследование: Когда объект обращается к свойству или методу, которого нет в его собственных свойствах, JavaScript автоматически обращается к его прототипу для поиска этого свойства или метода. Если свойство или метод не найдены на текущем прототипе, поиск продолжается по цепочке прототипов, пока не будет найдено или не достигнут самый верхний уровень прототипа (null).
  3. Создание прототипов: Прототип объекта может быть создан с использованием конструктора или литерала объекта с использованием свойства prototype. Например:

function Person(name) { this.name = name; } // Person.prototype.greet = function() { console.log("Hello, my name is " + this.name); }; // const person = new Person("Alice"); person.greet(); // Output: "Hello, my name is Alice"

  1. Наследование прототипа: Для наследования свойств и методов от другого объекта можно использовать функцию Object.create() или class и ключевое слово extends. Например:

function Student(name, major) { Person.call(this, name); this.major = major; } // Student.prototype = Object.create(Person.prototype); Student.prototype.constructor = Student; Student.prototype.study = function() { console.log(this.name + " is studying " + this.major); }; // const student = new Student("Bob", "Computer Science"); student.greet(); // Output: "Hello, my name is Bob" student.study(); // Output: "Bob is studying Computer Science"

В этом примере Student наследует свойства и методы от Person и добавляет собственный метод study().

228
Q

Плюсы и минусы JavaScript, предметная область и вариантов применения этой технологии

A

Плюсы JavaScript:
1. Кросс-платформенность: JavaScript поддерживается всеми основными браузерами и может работать на различных операционных системах.
2. Простота изучения: JavaScript имеет простой и понятный синтаксис, что делает его довольно доступным для изучения и использования.
3. Широкий набор инструментов и библиотек: JavaScript обладает огромным количеством инструментов, библиотек и фреймворков, которые облегчают разработку в различных предметных областях.
4. Небольшой размер кода: Компактность кода JavaScript позволяет эффективно передавать его по сети, что способствует быстрой загрузке и разработке веб-приложений.
5. Широкие возможности: JavaScript позволяет создавать различные типы веб-приложений, включая интерактивные веб-сайты, одностраничные приложения, мобильные приложения и даже серверные приложения.

Минусы JavaScript:
1. Ограничения безопасности: JavaScript работает в контексте клиента и имеет ограничения безопасности из-за политики одного источника (Same Origin Policy), которые ограничивают взаимодействие с другими доменами.
2. Интерпретируемый язык: Интерпретация кода JavaScript может занимать больше времени по сравнению с компилируемыми языками, такими как Java или C++. Это может привести к медленному выполнению приложений или увеличению нагрузки на систему.
3. Ограниченные возможности манипуляции с файловой системой: JavaScript имеет ограниченные возможности работы с файловой системой из-за безопасности и доступа к файлам на клиентском компьютере.
4. Зависимость от среды выполнения: JavaScript выполняется в контексте браузера или среды выполнения, что означает, что его возможности могут быть ограничены или отличаться в разных средах.

229
Q

Использование регулярных выражений. Когда приемлемо / неприемлемо? Как они работают? Как можно сделать читаемым код?

A

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

  1. Поиск и замена: Регулярные выражения можно использовать для поиска и замены подстрок в тексте. Например, если вам нужно заменить все вхождения определенного слова в тексте на другое слово или фразу, регулярные выражения могут справиться с этой задачей.
  2. Валидация данных: Регулярные выражения позволяют проверить соответствие введенных данных определенному шаблону. Например, вы можете использовать регулярное выражение, чтобы проверить правильность формата электронной почты, номера телефона или даты.
  3. Извлечение информации: Если вам нужно извлечь определенные куски информации из текста, вы можете использовать регулярные выражения для поиска и извлечения этих данных. Например, вы можете использовать регулярные выражения для извлечения всех ссылок из HTML-кода веб-страницы.

Однако, стоит отметить, что регулярные выражения могут быть сложными для понимания и поддержки. Если регулярное выражение становится слишком сложным, оно может стать трудным для чтения и понимания. Рекомендуется добавлять комментарии к регулярному выражению или разбивать его на несколько строк, чтобы сделать его более читаемым и понятным для других разработчиков. Использование названий групп и хорошего оформления кода также может сделать регулярные выражения более понятными.

230
Q

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

A

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

  1. Совместное использование хранилища данных: Все вкладки, открывающие страницы с одним доменом, могут иметь доступ к общим хранилищам данных, таким как локальное хранилище (localStorage), сеансовое хранилище (sessionStorage) и куки (cookies). Это позволяет обмениваться данными между вкладками с одним доменом.
  2. Message API: Браузеры предоставляют интерфейс Message для отправки сообщений между окнами и фреймами с разных источников. С помощью этого API вы можете отправлять и принимать сообщения между вкладками, но только если у вас есть доступ к окну или фрейму, к которому вы хотите отправить сообщение.
  3. Shared Web Workers: Общий Web Worker (Shared Web Worker) позволяет нескольким вкладкам использовать общий рабочий поток, чтобы выполнять задачи параллельно. Это позволяет вкладкам обмениваться данными и работать вместе, но требует явной привязки к общему рабочему потоку.
  4. Broadcast Channel API: Этот API позволяет вкладкам отправлять сообщения друг другу через именованный канал. Однако он поддерживается не всеми браузерами.

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

231
Q

Что такое Content Security Policy?

A

Content Security Policy (CSP) - это механизм безопасности веб-страниц, который позволяет разработчикам контролировать и ограничивать, какой контент и какие ресурсы могут быть загружены или выполнены на странице. CSP помогает предотвратить атаки типа XSS (межсайтовый скриптинг) и другие виды атак, связанных с загрузкой небезопасного или вредоносного контента на страницу.

CSP устанавливается с помощью HTTP-заголовка “Content-Security-Policy” и может содержать набор директив, которые определяют, какие источники контента допустимы на веб-странице. Например, вы можете настроить CSP таким образом, чтобы разрешить загрузку скриптов только из определенных доменов, запретить использование встроенных стилей или принудительно использовать HTTPS для загрузки ресурсов.

Преимущества использования CSP включают:
- Помощь в защите от атак межсайтового скриптинга и других видов веб-уязвимостей.
- Уменьшение потенциального ущерба от XSS-атак и других видов манипуляции контентом.
- Контроль загрузки внешних ресурсов и доменов на веб-странице.
- Улучшение безопасности и защиты данных пользователей.

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

232
Q

Как избежать загрузки кэшированных файлов скриптов и стилей?

A
  1. Добавление уникального параметра к URL-адресу файла:
    Один из наиболее распространенных способов - добавление уникального параметра, такого как временная метка или хеш, к URL-адресу файла скрипта или стиля. Это заставит браузер считать файл новым и загружать его снова при каждом обновлении страницы. Например:<link rel="stylesheet" href="styles.css?v=12345" /> <script src="script.js?v=12345"></script>

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

  1. Отключение кэширования в dev-режиме:
    Некоторые инструменты разработки или фреймворки предоставляют встроенную поддержку для отключения кэширования во время фронтенд-разработки. Например, в Next.js вы можете задать параметр cache в значении false в файле конфигурации next.config.js:module.exports = { // ...другая конфигурация... cache: false, };

Это заставит браузер игнорировать кэшированные файлы Javascript и CSS при разработке.

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

const randomString = Math.random().toString(36).substr(2, 10); const script = document.createElement('script'); script.src = script.js?${randomString}; document.head.appendChild(script);

Это генерирует новый URL-адрес скрипта каждый раз при обновлении страницы, заставляя браузер загружать новый файл.

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

233
Q

Что такое requestAnimationFrame?

A

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

Синтаксис метода requestAnimationFrame выглядит следующим образом:

requestAnimationFrame(callback);

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

Преимущества использования requestAnimationFrame включают:
- Автоматическая оптимизация производительности, так как браузер самостоятельно выбирает оптимальное время для выполнения анимации.
- Снижение нагрузки на процессор и увеличение срока службы батареи устройств.
- Предотвращение синхронизационных проблем, например, “дрожание” элементов, вызванных несовместимостью с обновлениями экрана.
- Автоматическое приостановление анимации, когда пользователь не находится на активной вкладке или когда браузер находится в фоновом режиме.

Использование requestAnimationFrame стало предпочтительным способом выполнения анимации вместо использования setInterval или setTimeout, так как этот метод предоставляет лучшую производительность и более точную синхронизацию с обновлениями экрана.

234
Q

Что такое Shadow DOM?

A

Shadow DOM (Document Object Model) - это функциональность, предоставляемая браузерами, которая позволяет создавать компоненты с ограниченной областью видимости для стилей и функциональности.

Когда вы создаете и используете Shadow DOM, вы создаете отдельное дерево DOM со своими собственными узлами и стилями, которые изолируются от внешнего дерева DOM страницы. Это позволяет создавать компоненты, которые не могут быть стилизованы или влиять на компоненты вне Shadow DOM.

Основные преимущества использования Shadow DOM:

  1. Изоляция стилей: Стили, определенные внутри Shadow DOM, применяются только к элементам внутри этого дерева DOM. Это предотвращает конфликты стилей между компонентами и внешней страницей.
  2. Изоляция функциональности: JavaScript-код, выполняемый внутри Shadow DOM, имеет доступ только к элементам внутри этого дерева DOM. Это помогает избежать конфликтов и несанкционированного доступа к DOM-элементам извне компонента.
  3. Переиспользование компонентов: Shadow DOM позволяет создавать компоненты с собственными стилями, разметкой и функциональностью, которые могут быть повторно использованы в разных частях веб-приложения или в разных проектах.
  4. Устойчивость к внешним стилям: Стили внутри Shadow DOM не подвержены изменениям внешних стилей, поэтому компоненты остаются неизменными, независимо от того, какие стили применяются к внешней странице.

Shadow DOM поддерживается веб-браузерами с помощью JavaScript API, такого как Element.attachShadow и ShadowRoot. Он находит применение в различных технологиях веб-разработки, таких как веб-компоненты, пользовательские элементы и некоторые фреймворки, которые стремятся создать изолированные компоненты.

235
Q

Сравните nextElementSibling и nextSibling.

A

nextElementSibling и nextSibling - это свойства DOM-узлов, которые предоставляют доступ к следующему соседнему элементу, расположенному на одном уровне иерархии DOM. Однако, есть некоторые различия между ними:

  1. nextSibling: Свойство nextSibling возвращает следующий соседний узел, независимо от того, является ли он элементом или текстовым узлом. Это означает, что nextSibling может возвращать текстовые узлы, комментарии или другие типы узлов, расположенные на том же уровне иерархии.
  2. nextElementSibling: Свойство nextElementSibling возвращает следующий соседний элемент-узел на том же уровне иерархии DOM. Оно игнорирует текстовые узлы, комментарии и другие типы узлов, возвращает только элементы. Если следующий соседний узел не является элементом, то возвращается значение null.

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

const element = document.getElementById('myElement'); console.log(element.nextElementSibling); // Возвращает следующий элемент-узел console.log(element.nextSibling); // Возвращает следующий узел (может быть не элементом)

236
Q

Расскажи о GraphQL.

A

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

Вот несколько ключевых принципов и функций GraphQL:

  1. Определение схемы:
    GraphQL использует схему для описания типов данных, доступных в API. Вы определяете типы объектов и их отношения, определяете точку входа запроса (корневые поля) и указываете, какие запросы и мутации могут быть выполнены. Схема GraphQL обычно задается с использованием языка схемы GraphQL (GraphQL Schema Language) или с помощью программатического API.
  2. Гибкие запросы и типизация:
    Вместо множества фиксированных конечных точек, как в REST, клиенты могут отправлять запросы GraphQL, содержащие только те данные, которые им нужны. Запросы GraphQL явно определяют требуемую структуру ответа и позволяют указывать вложенность и отношения между объектами. Также GraphQL предлагает строгую типизацию данных, поэтому клиенты заранее знают, какие данные ожидать от сервера.
  3. Единственный точка входа:
    В GraphQL существует только одна конечная точка, по которой клиенты отправляют все свои запросы. Это упрощает установку и поддержку API сервера.
  4. Резольверы и граф запросов:
    Резолверы работают как функции, которые извлекают запрошенные данные из различных источников или выполнения бизнес-логики, чтобы удовлетворить запросы клиента. Граф запросов GraphQL представляет соединения между резолверами и объектами в схеме для построения запрошенных данных.
  5. Поддержка мутаций:
    GraphQL позволяет клиентам не только запрашивать данные, но и отправлять мутации для изменения данных на сервере. Мутации позволяют выполнять операции создания, обновления и удаления данных.
  6. Интуитивный инструментарий разработчика:
    GraphQL обладает богатой экосистемой инструментов разработчика, включая клиентские библиотеки, серверные библиотеки, инструменты для разработки схем и просмотра схемы.

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

237
Q

Какие знаете метрики веб-сайта?

A

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

  1. Посещения (Visits): Число уникальных пользователей, которые посетили веб-сайт за определенный период времени.
  2. Сеансы (Sessions): Количество периодов активности пользователей на веб-сайте. Сессия начинается, когда пользователь заходит на сайт и заканчивается, когда он уходит или остается неактивным в течение определенного времени (обычно 30 минут).
  3. Просмотры страниц (Pageviews): Количество просмотров конкретных страниц веб-сайта. Один пользователь может просматривать несколько страниц в рамках одной сессии.
  4. Продолжительность сессии (Session Duration): Среднее время, которое пользователь проводит на вашем веб-сайте в рамках одной сессии.
  5. Скорость загрузки страницы (Page Load Time): Время, необходимое для полной загрузки страницы. Быстрая скорость загрузки важна для улучшения пользовательского опыта.
  6. Возвраты (Bounce Rate): Процент пользователей, которые покинули сайт после просмотра только одной страницы. Высокий показатель отказов может указывать на проблемы с контентом или пользовательским опытом.
  7. Конверсии (Conversions): Достижение желаемой цели веб-сайта, такой как заполнение формы, совершение покупки и других действий, которые приводят к конверсии посетителей в клиентов.
238
Q

Что такое git flow

A

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

  1. Основные ветки:
    Git Flow определяет две основные ветки в Git:
    • master: ветка master представляет стабильную версию кода. Код в этой ветке всегда должен быть готовым к развертыванию.
    • develop: ветка develop является главной веткой разработки. В нее вливаются все новые фичи и другие ветки перед их публикацией.
  2. Вспомогательные ветки:
    Git Flow определяет три вида вспомогательных веток:
    • feature: ветки feature используются для добавления новой функциональности в проект. Они создаются от develop и вливаются обратно в develop после завершения работы.
    • release: ветки release используются для подготовки новых релизов проекта. Они создаются от develop и вливаются как в master, так и в develop после завершения тестирования и подготовки к релизу.
    • hotfix: ветки hotfix используются для быстрого исправления ошибок в производственной версии кода. Они создаются от master и вливаются как в master, так и в develop после завершения исправления.
  3. Работа с ветками:
    Все описанные ветки создаются и сливаются в соответствии с определенными правилами и процессом Git Flow. Например, новые фичи разрабатываются в отдельных ветках feature, затем вливаются в develop. Релизы создаются из develop в ветках release и сливаются обратно как в master, так и в develop. Багфиксы создаются в “горячих” ветках hotfix и сливаются как в master, так и в develop.

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

Важно отметить, что Git Flow - это методология разработки, и каждая команда или проект может адаптировать ее под свои потребности и процессы.

239
Q

Что означает требование делать squash commits во время rebase?

A

Требование делать squash commits во время rebase означает объединение нескольких коммитов в один, чтобы облегчить чтение истории коммитов и сделать ее более понятной и логичной.

При выполнении операции rebase, где вы переносите коммиты из одной ветки на другую или преобразуете историю коммитов в некоторый другой способ, вы можете столкнуться с запросом на объединение (squash) одного или нескольких коммитов. В результате объединения коммиты будут объединены в один коммит с комментариями объединенных коммитов.

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

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

240
Q

Какие конвенции знаете и используете для git?

A

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

  1. Организация репозитория:
    - Используйте дескриптивные и понятные имена для репозиториев.
    - Разделяйте проекты на отдельные репозитории согласно их функциональности.
    - Сохраняйте репозиторий чистым и избегайте добавления ненужных файлов или файлов, не относящихся к коду.
  2. Наименование веток:
    - Дайте веткам понятные и описательные имена.
    - Используйте осмысленные префиксы (например, feature/, bugfix/) для указания типа задачи.
  3. Коммиты:
    - Используйте осмысленные сообщения коммитов, описывающие выполняемые изменения.
    - Соблюдайте единообразие в форматировании сообщений коммитов (например, “[тип задачи] Описание коммита”).
  4. Слияния (мерджи):
    - Избегайте сознательных изменений в слияниях, если только это не является частью задания слияния или исправления конфликтов.
  5. Игнорирование файлов:
    - Используйте файл .gitignore, чтобы указать, какие файлы или директории должны быть игнорированы Git.
241
Q

Для чего нужен package-lock.json?

A

Файл package-lock.json является частью экосистемы Node.js и используется для сохранения точной исходной составляющей зависимостей проекта. Вот несколько причин, почему package-lock.json важен:

  1. Фиксация версий зависимостей: package-lock.json содержит полный список всех зависимостей проекта, включая их точные версии. Это позволяет обеспечить консистентность версий зависимостей между разными средами разработки и развёртывания, а также между разными разработчиками. Это особенно полезно при коллективной работе над проектом.
  2. Более надёжная установка пакетов: package-lock.json содержит информацию о дереве зависимостей, включая вложенные зависимости и дистрибутивные файлы для каждого пакета. Это гарантирует, что при установке зависимостей будут загружены и установлены конкретные версии пакетов из package-lock.json, а не самые последние версии из веб-репозитория. Таким образом, это обеспечивает более надежный процесс установки и предотвращает неожиданные изменения в зависимостях.
  3. Ускорение процесса установки: package-lock.json содержит кэшированные и предкомпилированные файлы для каждого пакета. Это позволяет ускорить процесс установки зависимостей, т.к. не требуется повторная загрузка исходных файлов пакетов для каждой установки.
242
Q

В чем разница между npm install и npm ci?

A

npm install и npm ci - это две различные команды в NPM (Node Package Manager) для установки зависимостей проекта, но у них есть несколько ключевых различий:

  1. Целевая аудитория:
    - npm install рекомендуется для ежедневной разработки и позволяет выполнять различные операции, такие как установка, обновление и удаление пакетов, а также управление зависимостями проекта.
    - npm ci предназначен для использования в среде непрерывной интеграции и непрерывной доставки (CI/CD) и предоставляет строгую и непрерывную установку зависимостей в соответствии с package-lock.json или npm-shrinkwrap.json.
  2. Файлы блокировки зависимостей:
    - npm install устанавливает зависимости, учитывая package.json и package-lock.json (или npm-shrinkwrap.json) для обеспечения консистентности версий и фиксирования зависимостей проекта.
    - npm ci пропускает package.json и полностью доверяет package-lock.json (или npm-shrinkwrap.json), чтобы установить зависимости без проверки и обновления файлов блокировки зависимостей.
  3. Быстродействие:
    - npm install может быть медленной в процессе установки, особенно при наличии большого числа зависимостей, поскольку он также выполняет проверку изменений в блокировочных файлах, обновление пакетов и другие операции.
    - npm ci оптимизирована для быстрого времени установки и не выполняет дополнительные проверки или обновления, обеспечивая более быструю и потенциально предсказуемую установку зависимостей.
243
Q

Для чего нужны бандлеры?

A

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

  1. Управление зависимостями: Бандлеры позволяют импортировать, управлять и использовать зависимости из разных модулей и файлов в вашем проекте. Они обеспечивают разрешение конфликтов зависимостей и автоматически импортируют необходимые ресурсы, что упрощает и улучшает организацию кода.
  2. Модульность: Бандлеры поддерживают модульную структуру кода, что позволяет разделить код на независимые модули с четкими интерфейсами и зависимостями. Это улучшает читаемость и поддерживаемость кода, а также позволяет повторно использовать модули в других проектах.
  3. Обработка различных типов файлов: Бандлеры предоставляют возможность работать с различными типами файлов, такими как JavaScript, CSS, HTML, изображения и другие ресурсы. Они могут выполнять обработку исходного кода, включая транспиляцию, компиляцию, минификацию, оптимизацию и другие преобразования, чтобы оптимизировать работу и размер итогового бандла.
  4. Ленивая загрузка: Бандлеры поддерживают загрузку только тех модулей и ресурсов, которые необходимы для текущей страницы или функциональности. Это позволяет ускорить время загрузки и уменьшить начальные нагрузки, особенно для крупных проектов с множеством кода и ресурсов.

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

244
Q

Чем различаются git merge и git rebase?

A
  1. git merge: Команда git merge объединяет изменения из одной ветки в текущую ветку. При выполнении слияния Git создает новый коммит с объединенными изменениями, сохраняя исходную историю коммитов обеих веток. Это создает линейную историю слияний и позволяет в будущем отслеживать исходную историю каждой ветки. git merge является более простым и предпочтительным способом объединения изменений, особенно в случае, когда история коммитов не критически важна.
  2. git rebase: Команда git rebase переносит изменения из одной ветки на другую, перебазируя историю коммитов на новую базовую ветку. Вместо создания нового коммита с объединенными изменениями, Git переписывает историю коммитов путем применения каждого коммита из исходной ветки к конечной ветке. Это позволяет создать более линейную историю коммитов без дополнительных комитов слияния. Однако, переписывание истории коммитов может создавать проблемы, если изменения уже были опубликованы или используются другими разработчиками.
245
Q

Что такое staging area в git?

A

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

Когда вы работаете с Git, ваш рабочий каталог содержит набор файлов и каталогов, а также индекс, или staging area. Индекс отслеживает изменения в ваших файлах и подготавливает их для коммита. Вы можете добавлять, удалать или изменять изменения в staging area перед фиксацией их в коммите. Затем, когда вы выполняете команду git commit, Git записывает перечисленные изменения в новый коммит.

Использование staging area позволяет гибко работать с коммитами в Git, так как вы можете подготовить определенные файлы или части файлов для фиксации и оставить другие изменения для следующего коммита. Это также позволяет вам проверить свои изменения перед фиксацией и вносить корректировки, если это необходимо, прежде чем закреплять их в рамках коммита.

246
Q

Опишите процесс code review. Назовите основные правила, способы разрешения конфликтов и споров во время его проведения.

A

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

Основные правила code review включают:

  1. Установление стандартов: Убедитесь, что команда имеет четкую и согласованную документацию о требованиях и стилях кодирования, чтобы каждый знал, какие правила нужно соблюдать и что ожидается от проверки кода.
  2. Регулярность и своевременность: Code review следует проводить регулярно и в назначенные сроки, чтобы предотвратить задержки в процессе разработки и обеспечить непрерывное повышение качества.
  3. Культура конструктивной обратной связи: Коммуникация при проведении code review должна быть конструктивной, уважительной и объективной. Используйте ясные и специфичные комментарии, чтобы помочь автору улучшить код.
  4. Проверка правильности решения задачи: Убедитесь, что код решает поставленную задачу и соответствует бизнес-требованиям и функциональным спецификациям.

Способы разрешения конфликтов и споров во время проведения code review:

  1. Диалог и обсуждение: Откройте диалог с автором кода и обсудите возможные проблемы и предложения по улучшению. Дайте возможность автору объяснить свое решение и выслушайте его точку зрения.
  2. Постепенные улучшения: Если обнаружены проблемы, предложите постепенные улучшения, чтобы не перегружать автора большим количеством изменений, которые могут быть сложны для восприятия.
  3. Постепенное внедрение изменений: Если разработчики не согласны на какую-то часть кода, могут быть предложены компромиссы или постепенное внедрение изменений для устранения споров и поиск консенсуса.
  4. Обоснование: Если возникла необходимость отклонить предложение или изменения автора, обоснуйте ваше решение и приведите аргументы, чтобы помочь автору понять причины.

Важно помнить, что code review - это коллективная ответственность команды, и все ее члены должны использовать этот процесс для повышения качества кода, обмена опытом и непрерывного самоусовершенствования.

247
Q

Что такое CI/CD

A

CI/CD (Continuous Integration/Continuous Delivery) - это практика и набор методов и инструментов, обеспечивающих автоматизацию и непрерывность внедрения и доставки приложений.

Continuous Integration (непрерывная интеграция) - это процесс объединения кода и его автоматической сборки и проверки на соответствие при каждом изменении. Целью CI является ускорение и облегчение процесса разработки, обеспечение быстрой обратной связи и выявление ошибок на раннем этапе.

Continuous Delivery (непрерывная доставка) - это практика автоматической подготовки приложения к выпуску на каждом этапе разработки, начиная от размещения в системе контроля версий до окончательной доставки в производственную среду. Цель CD состоит в минимизации ручной работы, сокращении времени до выпуска и максимизации надежности и гибкости процесса доставки.

СI/CD дает возможность быстро и надежно поставлять новый функционал и исправления ошибок пользователю, а также автоматически тестировать, собирать, развертывать и проверять работоспособность приложения. Он способствует улучшению качества, сокращению времени разработки и доставки, а также упрощению процессов и стандартизации в разработке программного обеспечения.

248
Q

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

A

1XX (Информационные):

  • 100 Continue
  • 101 Switching Protocols
  • 102 Processing

2XX (Успешные):

  • 200 OK
  • 201 Created
  • 202 Accepted
  • 204 No Content
  • 206 Partial Content

3XX (Перенаправления):

  • 300 Multiple Choices
  • 301 Moved Permanently
  • 302 Found
  • 304 Not Modified
  • 307 Temporary Redirect
  • 308 Permanent Redirect

4XX (Ошибки клиента):

  • 400 Bad Request
  • 401 Unauthorized
  • 403 Forbidden
  • 404 Not Found
  • 405 Method Not Allowed
  • 409 Conflict
  • 410 Gone
  • 415 Unsupported Media Type
  • 418 I’m a teapot

5XX (Ошибки сервера):

  • 500 Internal Server Error
  • 501 Not Implemented
  • 502 Bad Gateway
  • 503 Service Unavailable
  • 504 Gateway Timeout
  • 505 HTTP Version Not Supported
249
Q

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

A

Cross-Origin Resource Sharing (CORS) - это механизм, предоставляемый браузером, который позволяет веб-страницам запрашивать ресурсы с другого домена (origin). Эта политика безопасности браузера предотвращает выполнение запросов на разные домены, если сервер не выдает соответствующие заголовки разрешения.

Для устранения проблем с CORS можно применить следующие подходы:

  1. Добавление заголовков CORS на сервере: Сервер должен включать заголовки CORS в ответе на запросы с других доменов. Наиболее часто используемый заголовок - “Access-Control-Allow-Origin”, который указывает, какие домены могут получать доступ к ресурсам. Если вы хотите разрешить доступ со всех доменов, вы можете указать значение “*”, но это может представлять угрозу безопасности и рекомендуется указать только разрешенные домены.
  2. Использование прокси-сервера: Если вы не имеете контроля над сервером, с которого запрашиваются ресурсы, вы можете настроить прокси-сервер, который будет получать запрошенные ресурсы с другого домена и передавать их клиенту на вашем домене. Таким образом, запросы выполняются с того же домена, и проблема с CORS не возникает.
  3. Использование JSONP (JSON with Padding): JSONP - это способ обойти политику безопасности браузера и получать данные с других доменов. Он использует тег скрипта (script tag), чтобы загрузить скрипт с другого домена, и вызывает функцию обратного вызова, чтобы передать данные на ваш домен. Однако JSONP имеет определенные ограничения и может быть уязвимым для атак.
  4. Использование CORS-прокси: Может быть использован CORS-прокси, который подставляется между клиентом и сервером и добавляет необходимые заголовки CORS в ответы, полученные от сервера. Это может быть полезным, когда сервер не поддерживает или не настроен для обработки CORS.
250
Q

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

A

Максимальный размер cookie может варьироваться в зависимости от браузера и операционной системы. Обычно, максимальный размер cookie составляет около 4 килобайт. Однако, существуют некоторые ограничения:

  1. В некоторых браузерах максимальный размер cookie может быть ограничен до 4096 байт.
  2. Веб-серверы могут устанавливать дополнительные ограничения на размер cookie.
  3. Некоторые операционные системы или браузеры могут иметь ограничение на общее количество cookie для одного домена.

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

251
Q

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

A

Статическая и динамическая типизация - это два подхода к управлению типами данных в программировании.

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

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

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

252
Q

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

A

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

Вот общий процесс взаимодействия клиента и сервера:

  1. Клиент отправляет запрос серверу. Запрос включает в себя информацию о том, какие данные или услуги клиент запрашивает, например, URL веб-страницы, метод API или другие параметры.
  2. Сервер получает запрос от клиента. Он анализирует запрос, определяет, какие данные или услуги требуются, и подготавливает ответ.
  3. Сервер обрабатывает запрос и выполняет соответствующие действия, например, извлекает данные из базы данных или вычисляет результат.
  4. Сервер формирует ответ, содержащий запрошенные данные или результат выполнения операции.
  5. Сервер отправляет ответ клиенту, используя протокол связи, такой как HTTP или TCP/IP. Ответ может включать данные, ошибки или статус операции.
  6. Клиент получает ответ от сервера и обрабатывает его. Он может отображать данные на экране пользователя, использовать их для дальнейших вычислений или выполнить другие операции в зависимости от приложения или услуги, которые он предоставляет клиенту.
  7. Взаимодействие между клиентом и сервером может продолжаться путем отправки дополнительных запросов и получения ответов, если это требуется для работы приложения или сервиса.

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

253
Q

Как проверить, является ли число конечным в JS?

A

В JavaScript можно использовать функцию isFinite() для проверки, является ли число конечным. Функция isFinite() возвращает значение true, если число является конечным, и false, если число является бесконечным или NaN (Not a Number). Вот пример использования функции isFinite():

let number1 = 10; let number2 = Infinity; let number3 = NaN; console.log(isFinite(number1)); // true console.log(isFinite(number2)); // false console.log(isFinite(number3)); // false

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

254
Q

Чем отличается поведение isNaN() и Number.isNaN()?

A

Функции isNaN() и Number.isNaN() предназначены для проверки, является ли значение не числом (NaN - Not-A-Number). Однако, они имеют некоторые отличия в своем поведении:

  • isNaN() является глобальной функцией JavaScript и выполняет преобразование аргумента в число при его необходимости. Если аргумент не может быть преобразован в число или является NaN, то функция возвращает true. Однако, isNaN() имеет некоторые особенности: она преобразует аргумент в число перед проверкой, что может привести к неожиданным результатам и ложным срабатываниям. Например, isNaN("123") будет false, поскольку строка “123” может быть преобразована в число.
  • Number.isNaN() является статическим методом объекта Number и не выполняет преобразование типов. Он строго проверяет, является ли аргумент NaN, и возвращает true только в случае, если аргумент является NaN. Например, Number.isNaN("123") будет false, поскольку строка “123” не является NaN.

Резюмируя, isNaN() преобразует аргумент в число перед проверкой, а Number.isNaN() выполняет строгое сравнение с NaN. Если вам требуется точная проверка на NaN, рекомендуется использовать Number.isNaN(), чтобы избежать непредвиденного преобразования типов.

255
Q

Сравните подходы работы с асинхронным кодом: сallbacks vs promises vs async / await.

A

Callback-функции, промисы и ключевые слова async/await - это три различных подхода к работе с асинхронным кодом в JavaScript. Они предлагают разные методы управления асинхронным выполнением и обработкой результатов. Вот краткое сравнение этих подходов:

  1. Callback-функции:
    - Callback-функции - это стандартный метод управления асинхронным кодом в JavaScript.
    - Функция передается в качестве аргумента в другую функцию и вызывается после завершения асинхронной операции.
    - Может возникнуть проблема “callback hell” при обработке нескольких асинхронных операций последовательно.
    - Обработка ошибок может быть сложной и требует каждый раз проверять наличие ошибок.
  2. Промисы:
    - Промисы - это объекты, представляющие результат или отсутствие результата асинхронной операции.
    - Позволяют обрабатывать успешное выполнение и обработку ошибок с помощью методов then() и catch().
    - Чейнинг методов then() позволяет выполнять последовательные операции над результатами нескольких асинхронных вызовов.
    - Промисы могут быть объединены при помощи метода Promise.all() для ожидания выполнения нескольких асинхронных операций.
  3. Async/await:
    - Async/await - это синтаксический сахар над промисами, который позволяет писать асинхронный код в более “синхронном” стиле.
    - Ключевое слово async объявляет функцию, которая выполняется асинхронно.
    - Ключевое слово await может использоваться внутри async функции для ожидания завершения промиса.
    - Ошибки могут быть обработаны с помощью конструкции try/catch вокруг await оператора.

Каждый из этих подходов имеет свои преимущества и недостатки, и выбор подхода зависит от требований проекта и предпочтений разработчика. Async/await является более новым и предпочтительным подходом к работе с асинхронным кодом, так как предоставляет чистый и понятный синтаксис. Однако, промисы и callback-функции могут быть более удобными в некоторых случаях или существующем коде.

256
Q

Можно ли записывать новые свойства / функции в прототипы стандартных классов (Array, Object и т. д.)? Почему нет? В каких случаях это делать можно? Как обезопасить себя, если нужно расширить прототип?

A

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

Однако, есть определенные рекомендации и ограничения, которые следует учитывать:

  1. Изменение прототипов стандартных классов может иметь глобальный эффект на все экземпляры этих классов в вашем приложении. Это может привести к потенциальным конфликтам и сложностям в сопровождении кода.
  2. Изменение прототипов стандартных классов может противоречить принципам модульности и инкапсуляции, особенно в случае коллаборативной разработки или больших проектов.
  3. Модификация прототипов стандартных классов может вызвать несовместимость или проблемы совместимости с будущими версиями языка JavaScript или другими библиотеками.

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

  1. Будьте осторожны и избирательны в выборе методов и свойств для добавления в прототипы стандартных классов. Убедитесь, что ваше расширение не конфликтует с уже существующими методами или свойствами.
  2. Документируйте изменения, чтобы другие разработчики знали, что прототип был изменен, и понимали, как использовать новые функции или свойства.
  3. Рассмотрите использование других паттернов, таких как миксины или создание собственных классов, вместо прямой модификации прототипов стандартных классов.

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

  • Используйте уникальные имена для своих методов и свойств в прототипе, чтобы избежать возможных конфликтов с будущими версиями языка или другими библиотеками.
  • Перебирайте свойства только тогда, когда они действительно отсутствуют, чтобы не перезаписывать существующие свойства или методы.
  • При добавлении новых методов или свойств рекомендуется использовать Object.defineProperty(), чтобы явно указать атрибуты свойства, такие как enumerable, writable и configurable, для большей контроля и безопасности.

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

257
Q

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

A

В JavaScript для перебора элементов массива существует несколько методов, включая forEach(), map(), filter(), reduce(), some(), every() и find(). Ниже я приведу краткое описание каждого метода и их отличия:

  1. forEach(): Метод forEach() вызывает переданную функцию обратного вызова для каждого элемента массива. Он не возвращает новый массив и не изменяет исходный.
  2. map(): Метод map() создает новый массив, в котором каждый элемент является результатом вызова переданной функции обратного вызова для каждого элемента исходного массива.
  3. filter(): Метод filter() создает новый массив, содержащий только те элементы исходного массива, для которых функция обратного вызова возвращает true.
  4. reduce(): Метод reduce() применяет функцию обратного вызова к аккумулятору и каждому элементу массива (слева направо) с целью свести массив к одному значению. Он возвращает это окончательное значение аккумулятора.
  5. some(): Метод some() проверяет, удовлетворяет ли хотя бы один элемент массива условию, заданному в функции обратного вызова. Возвращает true, если хотя бы один элемент удовлетворяет условию, и false в противном случае.
  6. every(): Метод every() проверяет, удовлетворяют ли все элементы массива указанному условию в функции обратного вызова. Возвращает true, если все элементы удовлетворяют условию, и false в противном случае.
  7. find(): Метод find() возвращает первый элемент массива, для которого функция обратного вызова возвращает true. Если такой элемент не найден, возвращается undefined.

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

258
Q

Какая разница между декларацией функции (function declaration) и функциональным выражением (function expression) и стрелочной функцией?

A
  1. Декларация функции (Function Declaration):
    function add(x, y) { return x + y; }
    - Декларация функции создает и инициализирует переменную в текущей области видимости.
    - Функция может быть вызвана до самого определения, называется “hoisting” (поднятие).
    - Имя функции является видимым во всей области видимости.
    - Используется для определения именованных функций.
  2. Функциональное выражение (Function Expression):
    const add = function(x, y) { return x + y; };
    - Функция присваивается переменной и трактуется как выражение.
    - Выражение функции не поднимается (не может быть вызвано до определения переменной).
    - Имя функции является видимым только внутри функции.
    - Переменная может быть использована для передачи функции в качестве аргумента или присвоения новому имени.
  3. Стрелочные функции (Arrow Functions):
    const add = (x, y) => x + y;
    - Стрелочные функции представляют сокращенный синтаксис для определения функций.
    - Они всегда анонимные и не могут быть назначены переменным с тем же именем.
    - Не имеют собственного контекста выполнения (this) и наследуют его от окружающего контекста.
    - Обычно используются для простых функций без необходимости использования ключевого слова this.

Разница между ними зависит от использования и контекста. Вообще:
- Декларации функций и стрелочные функции являются более подходящими для объявления функций, которые могут быть вызваны из любого места в коде.
- Функциональные выражения предпочтительны, когда функция используется в качестве значения, передается аргументом или присваивается переменной.
- Функция, объявленная как Function Declaration, создается интерпретатором до выполнения кода. Функцию объявленную как Function Expression можно создать и присвоить переменной как обычное значение.

Выбор между ними обычно зависит от предпочтений и требований конкретной задачи в вашем коде.

259
Q

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

A

Атрибуты async и defer используются для асинхронной загрузки скриптов в HTML-документе, но есть некоторые различия в их поведении:

Атрибут async:
- Скрипт, помеченный атрибутом async, загружается параллельно с парсингом HTML-документа.
- Когда скрипт загружен, он будет выполнен сразу же, без ожидания завершения парсинга HTML-документа и других скриптов.
- Порядок выполнения скриптов с атрибутом async не гарантирован. Если важен последовательный порядок выполнения скриптов, то async не подходит.
- Событие DOMContentLoaded может быть запущено до или после того, как асинхронный скрипт выполнится, в зависимости от времени его загрузки и выполнения.

Атрибут defer:
- Скрипт, помеченный атрибутом defer, также загружается параллельно с парсингом HTML-документа.
- Однако, выполнение отложено до тех пор, пока весь HTML-документ не будет полностью загружен.
- Скрипты с атрибутом defer будут выполняться в порядке их появления в HTML-документе.
- Событие DOMContentLoaded будет запущено после загрузки и перед выполнением всех скриптов с атрибутом defer.

Вывод:
- Если скрипты независимы друг от друга и очень важно, чтобы они были выполнены как можно быстрее, используйте async.
- Если скрипты зависят друг от друга или требуют доступа к DOM-элементам, используйте defer, чтобы гарантировать правильный порядок выполнения и доступ к контенту после его загрузки.

<!-- скрипт будет загружен и выполнен синхронно -->


<!-- скрипт будет загружен асинхронно -->


<!-- скрипт будет загружен асинхронно и выполнен после полной загрузки страницы -->


260
Q

Вы (20:16:21): Какая разница между свойствами HTML-элементов innerHTML и innerText?

A
  • innerHTML: Свойство innerHTML предоставляет доступ к HTML-содержимому элемента в виде строки. Оно позволяет как получать содержимое элемента в виде HTML, так и изменять его. Это означает, что вы можете внедрять HTML-код в элемент с помощью innerHTML, включая HTML-теги, атрибуты, стили и другие элементы.
    const element = document.getElementById("myElement"); console.log(element.innerHTML); // получаем HTML-содержимое элемента element.innerHTML = " Hello "; // изменяем HTML-содержимое элемента
  • innerText: Свойство innerText предоставляет доступ к текстовому содержимому элемента в виде строки. Оно возвращает только видимый текст, игнорируя все HTML-теги или элементы. При изменении содержимого с использованием innerText все HTML-теги будут интерпретироваться как обычный текст.
    const element = document.getElementById("myElement"); console.log(element.innerText); // получаем текстовое содержимое элемента element.innerText = "Hello"; // изменяем текстовое содержимое элемента

Таким образом, innerHTML позволяет работать с HTML-кодом элемента, включая его структуру и стили, в то время как innerText работает только с текстовым содержимым, игнорируя HTML-структуру. Выбор между ними зависит от конкретной задачи и требований.

261
Q

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

A

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

262
Q

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

A

Для остановки дефолтной обработки события в JavaScript можно использовать методы preventDefault(). Этот метод вызывается на объекте события и предотвращает выполнение стандартного действия, связанного с событием.

Для примера, предположим, у вас есть ссылка и вы хотите предотвратить переход по этой ссылке при клике на нее. Вы можете использовать preventDefault() в обработчике события клика для отмены дефолтного поведения:

const link = document.getElementById('myLink'); link.addEventListener('click', function(event) { event.preventDefault(); // предотвращаем переход по ссылке });

Таким образом, при клике на ссылку будет вызван обработчик события, и preventDefault() остановит выполнение стандартного действия - перехода по ссылке.

Также стоит отметить, что некоторые события могут иметь разные дефолтные действия, и в зависимости от контекста может потребовать дополнительных действий для полной остановки дефолтной обработки. Например, для полной остановки отправки формы при отправке данных через кнопку “submit” может потребоваться использование дополнительных методов, таких как stopPropagation(), чтобы предотвратить и другие действия связанные с обработкой события.

263
Q

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

A

Чтобы остановить всплытие (bubbling) события в JavaScript, вы можете использовать метод event.stopPropagation(). Этот метод вызывается в обработчике событий и предотвращает дальнейшее всплытие события на родительские элементы.

Пример использования метода stopPropagation():
element.addEventListener('click', function(event) { event.stopPropagation(); // остальной код обработки события });
В этом примере метод stopPropagation() вызывается в обработчике события click элемента, чтобы предотвратить всплытие события на родительские элементы.

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

264
Q

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

A

В JavaScript для получения высоты блока и его положения относительно границ документа вы можете использовать свойства offsetHeight и offsetTop элемента. Вот как это сделать:

  1. Получение высоты блока:
    let block = document.getElementById("blockId"); // Замените "blockId" на идентификатор вашего блока let blockHeight = block.offsetHeight; console.log(blockHeight);
    В этом примере мы используем offsetHeight, чтобы получить высоту блока.
  2. Получение положения блока относительно границ документа:
    let blockTop = block.offsetTop; console.log(blockTop);
    offsetTop вернет значение положения блока по вертикали от верхней границы документа.
265
Q

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

A

Значение this в обработчике событий (event handler) в JavaScript зависит от того, как обработчик событий был задан и вызван. В целом, значение this в обработчике событий указывает на элемент, к которому привязан обработчик.

Если обработчик событий был добавлен с помощью метода addEventListener(), то значение this в обработчике будет равно элементу, к которому был привязан обработчик:

Однако, если обработчик событий задан как атрибут HTML-элемента (например, onclick="..."), то значение this будет равно элементу, на котором произошло событие

266
Q

Чем отличается dev-сборка от prod?

A

Dev-сборка (разработческая сборка) и Prod-сборка (продуктовая/продакшн сборка) - это две различные конфигурации сборки проекта, которые используются в процессе разработки и в боевой среде соответственно. Вот основные отличия между ними:

  1. Режим отладки и оптимизация:
    - Dev-сборка предназначена для удобства разработчика. Она обычно включает режим отладки, расширенную информацию об ошибках и дополнительные инструменты разработчика. Производительность может быть ниже, так как приоритет удобства и быстрой обратной связи разработчика.
    - Prod-сборка оптимизирована для достижения максимальной производительности, надежности и минимизации размера проекта. Она может включать оптимизацию кода, минификацию и сжатие файлов, удаление неиспользуемого кода и другие оптимизации для повышения скорости и эффективности проекта.
  2. Расширение и просмотр ошибок:
    - Dev-сборка часто предоставляет более подробные сообщения об ошибках, расширенные трассировки стека и другие инструменты для обнаружения и отладки проблем во время разработки. Это помогает разработчикам быстро находить и исправлять проблемы.
    - Prod-сборка может скрывать некоторую информацию об ошибках и предоставлять более общие сообщения об ошибках, чтобы не раскрывать конфиденциальную информацию или детали внутренних механизмов проекта.
  3. Подключение сторонних пакетов и зависимостей:
    - Dev-сборка может включать отладочные или неоптимизированные версии сторонних пакетов, чтобы упростить разработку и облегчить отладку проблем, связанных с зависимостями.
    - Prod-сборка обычно использует оптимизированные и минифицированные версии сторонних пакетов и зависимостей, чтобы уменьшить размер финального бандла и улучшить производительность проекта.

В целом, dev-сборка и prod-сборка служат различным целям: первая - для разработки и отладки, а вторая - для оптимизации и предоставления рабочей версии проекта. Выбор между ними зависит от конкретных требований и условий проекта.

267
Q

Стайлгайд работы с гит

A
  1. Создание веток: Рекомендуется использовать отдельные ветки для разных функциональных изменений или исправлений ошибок. Это помогает изолировать исходные изменения и обеспечивает возможность легкого переключения между различными задачами.
  2. Частые коммиты: Различные внутренние изменения в Git лучше делать в виде небольших, смысловых коммитов. Это помогает в понимании последующих изменений и обеспечивает прозрачность истории изменений.
  3. Использование комментариев коммитов: Рекомендуется добавлять информативные комментарии к коммитам, чтобы получить понимание внесенных изменений без необходимости анализировать код.
  4. Удаление неиспользуемых веток: Необходимо периодически удалять ветки, которые больше не используются, чтобы уменьшить путаницу и ненужное загромождение репозитория Git.
  5. Использование .gitignore: Создание и обновление файла .gitignore, чтобы исключить ненужные файлы и папки из контроля версий.
  6. Разбиение больших изменений на мелкие: Большие изменения лучше разбивать на более мелкие и легче управляемые коммиты.
268
Q

Что делает команда git fetch?

A

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

Вот что делает команда git fetch:

  1. Получает информацию о доступных ветках и коммитах из удаленного репозитория.
  2. Обновляет локальные указатели на ветки (создает или обновляет ссылки на ветки) на основе удаленного репозитория.
  3. Загружает все новые коммиты, которых у вас еще нет в локальной копии репозитория.

Однако, важно отметить, что команда git fetch не автоматически обновляет ваши локальные ветки или рабочую директорию. Чтобы применить полученные изменения и объединить их с вашим текущим состоянием, вам нужно выполнить команду git merge или git rebase после git fetch.

Команда git fetch полезна, когда вы хотите получить обновления из удаленного репозитория, но хотите вручную решить, какие из этих обновлений применить в вашем локальном репозитории.

269
Q

Как можно получить символ строки по указанному индексу.

A
  1. str[0]: Вы можете использовать квадратные скобки и индекс для получения символа по определенному индексу в строке. Например, str[0] вернет символ в строке str по индексу 0. Этот способ доступа похож на доступ к элементам в массиве.
  2. str.charAt(0): Метод charAt() позволяет получить символ в строке по указанному индексу. Вы передаете индекс в качестве аргумента метода. Например, str.charAt(0) вернет символ в строке str по индексу 0.
  3. str.at(0): Метод at() был предложен, но на самом деле не существует в стандарте JavaScript для работы со строками. Метод at() не является встроенным методом строки. Вместо этого, используйте charAt() для получения символа по определенному индексу в строке.
270
Q

Как объединить строки?

A

Через конкатенацию,
бэктиками
или через concat(str1, str2, ...) - объединяет строки и возвращает новую строку.

271
Q

Как получить индекс первого вхождения подстроки в строке и последнего вхождения (с конца строки)?

A

indexOf(substring, startIndex) - возвращает индекс первого вхождения подстроки, начиная с указанного индекса.
const str = 'Hello World'; console.log(str.indexOf('o')); // 4 console.log(str.indexOf('o', 5)); // 7

String.prototype.lastIndexOf(): Метод lastIndexOf() возвращает индекс последнего вхождения указанного значения в строку. Если значение не найдено, метод вернет -1.

272
Q

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

A

substring(startIndex, endIndex) - возвращает часть строки от начального индекса до конечного индекса (не включая).
const str = 'Hello World'; console.log(str.substring(6, 11)); // 'World'

slice(startIndex, endIndex) - возвращает часть строки от начального индекса до конечного индекса (не включая). Работает аналогично методу substring().
const str = 'Hello World'; console.log(str.slice(6, 11)); // 'World'

273
Q

Как получить числовое значение Юникода для символа в строке по указанному индексу?

A

Метод charCodeAt() возвращает числовое значение Юникода для символа в строке по указанному индексу. Индексация начинается с 0. Если индекс находится за пределами длины строки, метод вернет NaN.

const str = "Hello World"; console.log(str.charCodeAt(0)); // 72 console.log(str.charCodeAt(6)); // 87

274
Q

Как проверить заканчивается ли строка указанным символом или начинается указанным символом?

A

String.prototype.endsWith(): Метод endsWith() проверяет, заканчивается ли строка указанным значением. Возвращает true, если строка заканчивается указанным значением, иначе возвращает false.

const str = "Hello World"; console.log(str.endsWith("World")); // true console.log(str.endsWith("Hello")); // false

String.prototype.startsWith(): Метод startsWith() проверяет, начинается ли строка с указанного значения. Возвращает true, если строка начинается с указанного значения, иначе возвращает false.

const str = "Hello World"; console.log(str.startsWith("Hello")); // true console.log(str.startsWith("Foo")); // false

275
Q

Проверить, что строка включает подстроку? А как проверить, сопоставление строки с регулярным выражением?

A

String.prototype.includes(): Метод includes() проверяет, содержит ли строка указанное значение. Возвращает true, если строка содержит указанное значение, иначе возвращает false.
const str = "Hello World"; console.log(str.includes("Hello")); // true console.log(str.includes("Foo")); // false

String.prototype.match(): Метод match() ищет сопоставление строки с регулярным выражением. Возвращает массив с найденными совпадениями или null.
const str = "Hello World"; console.log(str.match(/Hello/)); // ["Hello"] console.log(str.match(/Foo/)); // null

String.prototype.matchAll(): Метод matchAll() возвращает итератор, который содержит все совпадения строки с регулярным выражением.
const str = "Hello World"; const matches = str.matchAll(/o/g); for (const match of matches) { console.log(match[0]); // "o", "o" }

String.prototype.search(): Метод search() выполняет поиск указанного значения в строке с использованием регулярного выражения. Возвращает индекс первого совпадения или -1, если совпадение не найдено.
const str = "Hello World"; console.log(str.search(/World/)); // 6 console.log(str.search(/Foo/)); // -1

276
Q

Как сравнить две строки лексикографически?

A

String.prototype.localeCompare(): Метод localeCompare() сравнивает две строки лексикографически с учетом языковых настроек текущей локали. Возвращает отрицательное число, если первая строка меньше, положительное число, если первая строка больше, и 0, если строки равны.

const str1 = "Hello"; const str2 = "World"; console.log(str1.localeCompare(str2)); // -1 console.log(str2.localeCompare(str1)); // 1 console.log(str1.localeCompare(str1)); // 0

277
Q

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

A

String.prototype.trim(): Метод trim() удаляет пробельные символы с начала и конца строки и возвращает новую строку.
const str = " Hello World "; console.log(str.trim()); // "Hello World"

String.prototype.trimEnd(): Метод trimEnd() удаляет пробельные символы с конца строки и возвращает новую строку.

String.prototype.trimStart(): Метод trimStart() удаляет пробельные символы с начала строки и возвращает новую строку.

278
Q

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

A

String.prototype.repeat(): Метод repeat() создает и возвращает новую строку, состоящую из указанного числа копий исходной строки.
const str = "abc"; console.log(str.repeat(3)); // "abcabcabc" console.log(str.repeat(0)); // "" console.log(str.repeat(1)); // "abc"

String.prototype.padEnd(): Метод padEnd() добавляет указанный символ в конец строки так, чтобы строка имела заданную длину. Если длина строки уже достигнута или превышена, метод не изменяет строку.
const str = "Hello"; console.log(str.padEnd(10, "!")); // "Hello!!!!" console.log(str.padEnd(5)); // "Hello"

String.prototype.padStart(): Метод padStart() добавляет указанный символ в начало строки так, чтобы строка имела заданную длину. Если длина строки уже достигнута или превышена, метод не изменяет строку.
const str = "Hello"; console.log(str.padStart(10, "!")); // "!!!!Hello" console.log(str.padStart(5)); // "Hello"

279
Q

Как заменить часть строки другой подстрокой?

A

String.prototype.replace(): Метод replace() заменяет часть строки на другую строку или регулярное выражение, и возвращает новую строку.

String.prototype.replaceAll(): Метод replaceAll() заменяет все вхождения подстроки или регулярного выражения на заданную строку, и возвращает новую строку.

280
Q

GraphQL и REST API какая разница? Когда что использовать?

A

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

Наиболее распространенный сегодня стиль API был впервые описан в 2000 году Роем Филдингом в его докторской диссертации. REST делает доступными данные на стороне сервера, представляя их в простых форматах — чаще всего это JSON и XML.

Как работает REST
REST определен не так строго, как SOAP. RESTful-архитектура должна соответствовать шести архитектурным ограничениям:

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

Плюсы REST
Разделение клиента и сервера. По возможности разделяя клиент и сервер, REST обеспечивает лучшую абстракцию по сравнению с RPC. Система с уровнями абстракции способна инкапсулировать свои детали, чтобы лучше идентифицировать и поддерживать свои свойства. Поэтому REST API достаточно гибок, чтобы развиваться с течением времени и при этом оставаться стабильной системой.

Открытость. Все описывается связью между клиентом и сервером, так что для понимания, как взаимодействовать с REST API, не требуется никакая внешняя документация.

Дружественность к кэшу. REST — единственный стиль, который позволяет кэшировать данные на уровне HTTP благодаря повторному использованию множества HTTP-инструментов. В то же время, реализация кэширования в любом другом API потребует настройки дополнительного модуля кэширования.

Поддержка нескольких форматов. Возможность поддержки нескольких форматов хранения и обмена данными — одна из причин, по которым REST в настоящее время преобладает в сфере создания общедоступных API.

Минусы REST
Нет единой структуры REST. Нет точного правильного способа создания REST API. Как моделировать ресурсы и какие ресурсы моделировать, будет зависеть от каждого сценария. Это делает REST простым в теории, но трудным на практике.

Большие полезные нагрузки. REST возвращает много богатых метаданных, так что клиент может понять все необходимое о состоянии приложения только из его ответов. И эта болтливость не имеет большого значения для большой сетевой трубы с большой пропускной способностью. Но это не всегда так. Это стало ключевым движущим фактором для Facebook, придумавшего описание стиля GraphQL в 2012 году.

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

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

Простые приложения, управляемые ресурсами. REST — это валидный подход для подключения приложений, управляемых ресурсами, которые не нуждаются в гибкости запросов.

GraphQL: запрос только необходимых данных
Для того, чтобы вернуть что-то нужное, требуется многократно вызывать REST API. И вот, чтобы изменить правила игры, был изобретен GraphQL.

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

Как работает GraphQL
GraphQL начинается с построения схемы, которая представляет собой описание всех запросов, которые возможно сделать в API GraphQL, и всех типов данных, которые они возвращают. Строить схему сложно, поскольку она требует строгой типизации на языке определения схемы (Schema Definition Language, SDL).

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

В дополнение к CRUD-операциям RESTful GraphQL содержит также подписки, которые позволяют в режиме реального времени получать уведомления от сервера.

Плюсы GraphQL
Типизированная схема. GraphQL заранее публикует то, что он может осуществить, что улучшает обнаруживаемость. Указывая клиенту на API GraphQL, мы можем узнать, какие запросы доступны.

Хорошо подходит для графических данных. Данные, которые находятся в глубоких отношениях связанности, но не годятся для плоских данных.

Никаких версий. Лучшая практика управления версиями — это вообще не версионировать API. В то время как REST предлагает несколько версий API, GraphQL использует единую развивающуюся версию, которая обеспечивает непрерывный доступ к новым функциям и способствует более чистому и удобному в обслуживании серверному коду.

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

Гибкие разрешения. GraphQL позволяет выборочно раскрывать определенные функции, сохраняя при этом личную информацию. Между тем архитектура REST не раскрывает данные порциями: либо все, либо ничего.

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

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

Много самообразования перед разработкой. Когда у них недостаточно времени, чтобы разобраться в нишевых операциях GraphQL и SDL, многие проекты решают пойти по известному пути REST.

Сценарии использования GraphQL
Мобильный API. В этом случае важна производительность сети и оптимизация полезной нагрузки единичного сообщения. И GraphQL предлагает более эффективную загрузку данных для мобильных устройств.

Сложные системы и микросервисы. GraphQL способен скрыть сложность нескольких интегрированных систем, лежащих в основе его API. Агрегируя данные из нескольких мест, он объединяет их в одну глобальную схему. Это особенно актуально для устаревших инфраструктур или сторонних API, которые расширились со временем.

281
Q

Модули в JS - что такое CJS?

A

CJS (CommonJS) — стандартные модули в NodeJS. Вот как это выглядит:

//importing
const doSomething = require(‘./doSomething.js’);

//exporting
module.exports = function doSomething(n) {…}

CJS синхронен и хорош для серверной части.

282
Q

Модули в JS - что такое AMD?

A

AMD (Asynchronous module definition) — что дословно переводится как «Асинхронное определение модуля», используется с RequireJS.

Вот пример кода:
define([‘dep1’, ‘dep2’], function (dep1, dep2) {
//Define the module value by returning a value.
return function () {};
});
или
// “simplified CommonJS wrapping” https://requirejs.org/docs/whyamd.html
define(function (require) {
var dep1 = require(‘dep1’),
dep2 = require(‘dep2’);
return function () {};
});

AMD асинхронна и хороша для внешнего интерфейса.

283
Q

Модули в JS - что такое UMD?

A

UMD (Universal Module Definition) — по сути своей это не модули, это паттерн для использования AMD и CJS в зависимости от энва. Стал популярен с приходом бандлеров, т.к. разные пакеты использовали разные системы модулей, а бандлерам нужно было все это дело как-то упаковывать. Вот как это может выглядеть ( источник ):
(function (root, factory) {
if (typeof define === “function” && define.amd) {
define([“jquery”, “underscore”], factory);
} else if (typeof exports === “object”) {
module.exports = factory(require(“jquery”), require(“underscore”));
} else {
root.Requester = factory(root.$, root._);
}
}(this, function ($, _) {
// this is where I defined my module implementation
var Requester = { // … };
return Requester;
}));

UMD работает везде и обычно используется как запасной вариант на случай, если ESM не работает.

284
Q

Модули в JS - что такое UMD?

A

ESM (EcmaScript Module) — самый свежий и единственный (CJS — был стандартом в ноде, но не в самом JS) стандарт модулей в JS. Кардинально отличается от CJS тем — что модули статичны. Т.е. зависимости и модули определяются до того как ранается код, поэтому в ESM на уровне синтаксиса нельзя переопределять значение экспорта (я имею ввиду нельзя поменять ссылку на экспорт, но если экспортится объект, его менять конечно же можно), import _, {} from ‘’ и export const | export default могут быть только на верхнем уровне файла . Благодаря статичным модулям, бандлеры могут без проблем делать Tree Shaking(удалять неиспользованные экспорты):
import React from ‘react’;
import {foo, bar} from ‘./myLib’;
export default function() {
// your Function
};
export const function1() {…};
export const function2() {…};

ESM — лучший формат модуля благодаря простому синтаксису, асинхронному характеру и возможности тряски дерева.

285
Q

Определение переменной (объявление) и инициализация переменной

A
  1. Определение переменной:
    Определение переменной означает указание ее имени и возможного типа данных, который может быть присвоен этой переменной. В JavaScript переменные определяются с помощью ключевых слов var, let или const. Например:
    let city
  2. Инициализация переменной - Initializing variable:
    Инициализация переменной - это присваивание начального значения переменной при ее создании либо впервые после объявления. Например:
    let city = "Lisboa"
  3. let city - объявление, декларирование переменной
  4. = “Lisboa” - присвоение значения (литерала)
286
Q

Что называют “объектами обёртками” ?

A

временные объекты, в которые преобразуются значения примитивного типа

287
Q

Ассоциативность операторов это

A

свойство, определяющее порядок обработки операторов с одинаковым приоритетом. Например, оператор доступа к свойствам объекта “.”, ассоциативен слева направо

  • Левая ассоциативность означает, что операторы выполняются слева направо. Если есть несколько операторов с одинаковым приоритетом, то первый оператор слева выполнится первым. Пример: 5 - 3 - 1 будет обработано как (5 - 3) - 1, поскольку вычитание является левоассоциативным оператором.
  • Правая ассоциативность означает, что операторы выполняются справа налево. Если есть несколько операторов с одинаковым приоритетом, то первый оператор справа выполнится первым. Пример: 2 ** 3 ** 2 будет обработано как 2 ** (3 ** 2), поскольку оператор возведения в степень (**) является правоассоциативным оператором.
288
Q

Какой оператор выполняет проверку на принадлежность объекта к указанному классу ?

A

В JavaScript, оператор instanceof используется для проверки принадлежности объекта к определенному классу. Оператор instanceof возвращает true, если объект является экземпляром указанного класса, и false в противном случае. Вот пример использования оператора instanceof:

class Person {
constructor(name) {
this.name = name;
}
}

const john = new Person(“John”);
console.log(john instanceof Person); // true

const str = “Hello”;
console.log(str instanceof String); // false

const num = 42;
console.log(num instanceof Number); // false

289
Q

Что такое итерация?

A

Каждое отдельное исполнение инструкций в теле цикла

290
Q

Что такое Call stack?

A

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

Event Loop имеет два основных компонента - Call Stack (стек вызовов) и Task Queue. Когда Call Stack пуст, он берет функцию из Task Queue и помещает ее в Call Stack для выполнения.

291
Q

Что такое Task Queue?

A

список задач, готовых к выполнению.

Task Queue (очередь задач) - это механизм в JavaScript, связанный с событийным циклом (Event Loop), который управляет асинхронными операциями и выполняет коллбэки функций в правильном порядке.

Когда в JavaScript выполняется асинхронная операция или запускается таймер, связанный с таймаутом или интервалом, коллбэк функция, связанная с этой операцией, помещается в Task Queue. Task Queue работает на принципе “первым пришел - первым вышел” (FIFO), то есть функции выполняются в том порядке, в котором они были добавлены в очередь.

Event Loop имеет два основных компонента - Call Stack (стек вызовов) и Task Queue. Когда Call Stack пуст, он берет функцию из Task Queue и помещает ее в Call Stack для выполнения.

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

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

292
Q

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

A

оператор typeof

var num = 42;
console.log(typeof num); // “number”

var str = “Hello”;
console.log(typeof str); // “string”

var bool = true;
console.log(typeof bool); // “boolean”

var arr = [1, 2, 3];
console.log(typeof arr); // “object”

var obj = { name: “John”, age: 30 };
console.log(typeof obj); // “object”

var func = function() { };
console.log(typeof func); // “function”

var undef;
console.log(typeof undef); // “undefined”

var n = null;
console.log(typeof n); // “object”

293
Q

Для чего нужен BOM?

A

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

BOM (Browser Object Model) — это часть веб-браузера, предоставляющая программный интерфейс для взаимодействия с окном браузера и другими элементами пользовательского интерфейса. BOM предоставляет различные объекты и методы для доступа и управления окном браузера, историей переходов, URL-адресами, cookie, таймерами, управления всплывающими окнами и другими функциями, которые связаны с окном и браузером.

Некоторые основные компоненты BOM включают:

  • Объект window: представляет окно браузера и предоставляет доступ к его свойствам и методам. Например, можно использовать объект window для получения размеров и координат окна, установки таймеров, открытия и закрытия всплывающих окон и т.д.
  • Объект navigator: предоставляет информацию о браузере, который запустил текущую страницу. Например, объект navigator может быть использован для определения пользовательского агента (User Agent), доступности функций браузера и других характеристик.
  • Объект location: предоставляет информацию о текущем URL-адресе страницы и позволяет изменять URL-адресы, загружать новые страницы, перенаправлять пользователя и т.д.
  • Объект history: предоставляет доступ к истории переходов пользователя между страницами, позволяет переходить вперед и назад по истории, управлять записями истории и т.д.
294
Q

Опишите, как работает прототипно-ориентированная модель наследования в JS.

A

В плане наследования JavaScript работает лишь с одной сущностью: объектами. Каждый объект имеет внутреннюю ссылку на другой объект, называемый его прототипом. У объекта-прототипа также есть свой собственный прототип и так далее до тех пор, пока цепочка не завершится объектом, у которого свойство prototype равно null. По определению, null не имеет прототипа и является завершающим звеном в цепочке прототипов.

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

295
Q

В чем заключается различие между host objects и native objects ?

A

Native objects — объекты определенные спецификацией ECMAScript, например, Object (constructor), Date, Math.

Host objects— объекты, чья роль заключается в создании исполнительного окружения для ECMAScript, например, window, document, location, history.

296
Q

За что отвечают и в чем заключается различие между feature detection, feature inference и User Agent String ?

A

Feature detection, feature inference и User Agent String — это практики определения, существует ли определенная функция веб-технологии в браузере.

Feature detection — это способ определить, существует ли функция в определенных браузерах.

Feature inference — предположение: если одна функция присутствует (или нет), соответственно другая тоже будет присутствовать (или нет).

User Agent String — это текстовая строка, которую отправляет каждый браузер и к которой можно получить доступ через navigator.userAgent. Эта строка содержит в себе информацию о исполнительном окружении.

297
Q

Какое минимальное время можно задать в setTimeout и setInterval?

A

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

298
Q

for (var i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i);
}, 100);
}
Возвращает 10 10 10 10 10 10 10 10 10 10
Придумай как можно больше вариантов, чтобы код отработал правильно

A
  1. Анонимная самовызывающаяся функция (IIFE, Immediately Invoked Function Expression):

for (var i = 0; i < 10; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
}, 100);
})(i);
}

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

  1. Использование метода bind():

for (var i = 0; i < 10; i++) {
setTimeout(function (i) {
console.log(i);
}.bind(this, i), 100);
}

В этом варианте метод bind() используется для создания новой функции, связанной с контекстом и передачей значения i как аргумента. Это позволяет сохранить значение i для каждой вызываемой функции setTimeout.

  1. Передача аргумента в setTimeout:

for (var i = 0; i < 10; i++) {
setTimeout(function (i) {
console.log(i);
}, 100, i);
}

В этом варианте третьим аргументом setTimeout явно передается значение i. Это позволяет сохранить значение i для каждой задержки setTimeout.

  1. Использование блока let:

for (let i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i);
}, 100);
}

В этом варианте используется блок let вместо var для объявления переменной i внутри цикла. Поскольку блок let создает новую переменную i для каждой итерации цикла, значение i сохраняется корректно для каждой задержки setTimeout.

299
Q

Какие преимущества и недостатки в использовании Ajax

A

Ajax (Asynchronous JavaScript and XML) позволяет веб-страницам обмениваться данными асинхронно с сервером без перезагрузки всей страницы. Это имеет несколько преимуществ и недостатков, которые стоит учитывать:

Преимущества использования Ajax:
1. Асинхронность: Одним из ключевых преимуществ Ajax является возможность асинхронной обработки запросов к серверу без блокировки пользовательского интерфейса. Это позволяет создавать более отзывчивые и динамические веб-приложения.
2. Обновление частей страницы: Ajax позволяет обновлять только части веб-страницы без необходимости перезагрузки всей страницы. Это помогает создавать более плавные и быстрые пользовательские интерфейсы.
3. Улучшенная производительность: Использование Ajax позволяет обмениваться данными с сервером в фоновом режиме, что может улучшить производительность и снизить нагрузку на сеть и сервер.
4. Лучший пользовательский опыт: Благодаря возможности обновления частей страницы без перезагрузки, Ajax помогает создавать более плавные и интерактивные пользовательские интерфейсы, улучшая общий опыт пользователя.

Недостатки использования Ajax:
1. Сложность: Использование Ajax может быть более сложным, чем простая синхронная передача данных. Это связано с управлением асинхронными запросами, обработкой ошибок и синхронизацией состояний.
2. Загрузка дополнительного кода: Для работы с Ajax необходимо использовать JavaScript, что может привести к дополнительной загрузке кода на стороне клиента. Это может повысить потребление ресурсов и увеличить время загрузки страницы.
3. Проблемы с безопасностью: Использование Ajax может повлечь за собой уязвимости безопасности, такие как атаки типа Cross-Site Scripting (XSS) или Cross-Site Request Forgery (CSRF). Необходимо принять соответствующие меры для защиты от таких угроз.

300
Q

Как можно оптимизировать загрузку внешних ресурсов на странице. Назовите 3 способа уменьшения времени загрузки страницы

A

Можно использовать кеширование, ленивую загрузку (lazy-loading), поддомены. Если используется HTTP/1.1, для HTTP/2 это неактуально.

Можно оптимизировать сборку JS-кода, минифицировать, использовать CDN, gzip-сжатие, css- и svg-спрайты, настроить кеширование.

  1. Минимизация количества запросов.
  2. Lazy-loading.
  3. Минификация CSS и JS.
301
Q

Сколько ресурсов браузер может одновременно загружать с одного домена

A

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

302
Q

Что такое REST и RESTful API?

A

REST (Representational State Transfer) — это архитектурный стиль, используемый при проектировании распределенных систем. Он был описан в диссертации Роя Филдинга в 2000 году и является основой для создания RESTful API.

RESTful API — это веб-сервис, который использует протокол HTTP для обмена данными. Он предоставляет возможность получать, создавать, обновлять и удалять данные на удаленном сервере, используя стандартные HTTP-методы (GET, POST, PUT, DELETE и т. д.).

RESTful API использует ресурсы (например, товары, пользователи, заказы) и URI (Uniform Resource Identifier) для доступа к этим ресурсам. Клиент отправляет запросы на сервер, указывая URI и метод HTTP, а сервер возвращает ответ, который может содержать данные в различных форматах (например, JSON или XML).

Клиент-серверная архитектура: сервер и клиент независимы друг от друга, что позволяет развивать их независимо.
Отсутствие состояния (stateless): каждый запрос клиента должен содержать всю необходимую информацию для его обработки, без сохранения состояния на сервере.
Кэширование: клиенты могут кэшировать ответы сервера, чтобы уменьшить количество запросов.
Единообразие интерфейса: единообразный интерфейс между клиентом и сервером упрощает взаимодействие и увеличивает его надежность.
Слои: клиент не должен знать о слоях на сервере, которые обрабатывают запросы.
RESTful API является широко используемым в веб-разработке и предоставляет удобный и гибкий способ обмена данными между сервером и клиентом.

303
Q

Что такое «трёхстороннее рукопожатие»?

A

Трехстороннее рукопожатие (Triple Handshake) — это проблема безопасности в компьютерных сетях, которая возникает при использовании SSL/TLS-соединений.

В процессе установки безопасного соединения SSL/TLS между клиентом и сервером происходит обмен сообщениями, который состоит из трех шагов (трехстороннее рукопожатие):

Клиент отправляет серверу сообщение SYN с произвольным начальным номером (seq).
Сервер отправляет клиенту сообщение SYN-ACK, подтверждающее получение сообщения SYN и содержащее свой собственный произвольный начальный номер (seq) и номер последовательности подтверждения (ack), который равен начальному номеру клиента +1.
Клиент отправляет серверу сообщение ACK с номером подтверждения, который равен начальному номеру сервера +1.
Проблема Triple Handshake возникает, когда злоумышленник нарушает правильный порядок шагов рукопожатия, вставляя свой сервер между клиентом и настоящим сервером. В этом случае злоумышленник может получить доступ к конфиденциальной информации, передаваемой между клиентом и сервером.

Чтобы избежать проблемы Triple Handshake, необходимо использовать проверенные и безопасные протоколы SSL/TLS и устанавливать соединение только с доверенными серверами.

304
Q

Как реализовать отложенную загрузку изображений?

A

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

Lazy Loading — техника, которая позволяет отложить загрузку изображений, находящихся за пределами видимой области. Для этого можно использовать библиотеки, такие как Lazysizes или Intersection Observer API.

Атрибуты data- — Вы можете использовать атрибут data- вместе с атрибутом src, чтобы отложить загрузку изображения

  1. Использование атрибута loading:
    - Добавьте атрибут loading="lazy" к ``.
    - Это позволит браузеру отложить загрузку изображения до тех пор, пока оно не будет видимым на экране пользователем при прокрутке страницы.
    - Например: Image.
  2. Использование JavaScript:
    - Замените исходные значения атрибута src на data-src (например, data-src="image.jpg").
    - Добавьте обработчик события для прокрутки страницы, который будет загружать изображения по мере их появления в области просмотра.
    - Пример кода на JavaScript:

const lazyImages = Array.from(document.querySelectorAll(‘img[data-src]’));

const lazyLoad = function() {
lazyImages.forEach(img => {
if (img.getBoundingClientRect().top <= window.innerHeight &&
img.getBoundingClientRect().bottom >= 0 &&
getComputedStyle(img).display !== ‘none’) {
img.src = img.dataset.src;
img.removeAttribute(‘data-src’);
}
});

lazyImages = lazyImages.filter(img => img.hasAttribute(‘data-src’));
if (lazyImages.length === 0) {
document.removeEventListener(‘scroll’, lazyLoad);
window.removeEventListener(‘resize’, lazyLoad);
}
};

document.addEventListener(‘scroll’, lazyLoad);
window.addEventListener(‘resize’, lazyLoad);
window.addEventListener(‘orientationchange’, lazyLoad);

  • В этом примере событие scroll, resize и orientationchange отслеживается, и когда изображение появляется в видимой области, его data-src заменяется на src.
305
Q

Что такое XSS (Cross-Site Scripting)?

A

XSS (Cross-Site Scripting) - это тип атаки на веб-приложение, при которой злоумышленник внедряет вредоносный код (обычно JavaScript) в веб-страницу или приложение, чтобы выполнить его на компьютере пользователя или получить доступ к его персональным данным. Атаки XSS возникают, когда веб-приложение недостаточно санитизирует или неэкранирует введенные пользователем данные, что позволяет злоумышленнику выполнить свой код в браузере пользователя.

Есть несколько типов атак XSS:

  1. Stored XSS: Вредоносный код сохраняется на сервере и потом выводится на страницу при ее загрузке или при запросах пользователей.
  2. Reflected XSS: Вредоносный код внедряется в URL-параметры, которые затем отображаются на странице или передаются пользователю в ответ на запрос.
  3. DOM-Based XSS: Вредоносный код изменяет DOM (Document Object Model) страницы непосредственно в браузере пользователя, влияя на различные компоненты и функциональность веб-приложения.

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

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

  1. Экранирование вводимых данных: Проверяйте и экранируйте (экранирование HTML-символов) все входные данные от пользователя, перед тем как выводить их на веб-страницу. Это предотвратит выполнение вредоносного кода.
  2. Валидация данных: Применяйте строгую валидацию пользовательского ввода на сервере и на клиентской стороне, чтобы проверить, что данные являются допустимыми и соответствуют ожидаемому формату.
  3. Ограничение использования HTML и JavaScript: Следует ограничивать возможности пользователей использовать HTML и JavaScript на странице. Например, не разрешайте вводить HTML-теги или скрипты в формы и поля ввода.
  4. Установка правильных заголовков Content Security Policy (CSP): CSP позволяет настроить политику безопасности для ограничения и контроля ресурсов, которые может загружать страница. Это может помочь предотвратить выполнение вредоносного кода.
  5. Использование HTTPOnly флага для кук: Установка флага HTTPOnly для кук позволяет предотвратить доступ к ним из JavaScript и защищает от кражи сессионных данных.
306
Q

Как подключить js, css? Плюсы, минусы разных способов?

A

Можно с помощью тегов


<style></style>

прямо на странице или

<link></link>

подключаем из внешних файлов.

Минус подключения внешних файлов заключается в том, что для их скачки, открываются дополнительные соединения. Может случиться так, что мы не сможем закачать, а если это еще и js файл, подключенный где-то в начале, то мы рискуем показать пользователю пустую страницу.
Размещение стилей и скриптов в самом документе, в этом плане, надежнее. Но при этом скрипты и стили совершенно не кешируются.

307
Q

Объясни как именно происходят процессы в браузере, когда человек вводит url в браузере и открывается страница. Что и как отрабатывает по пунктам? Какой запрос посылается и куда.

A
  1. Парсинг URL: Браузер анализирует введенный URL и разбирает его на составные части, такие как протокол (например, HTTP или HTTPS), доменное имя (например, www.example.com) и путь к ресурсу на сервере (например, /index.html).
  2. DNS-разрешение: Браузер проверяет DNS-кэш или отправляет запрос DNS-серверу, чтобы получить IP-адрес для заданного доменного имени. Этот шаг позволяет браузеру узнать, к какому серверу отправлять запросы.
  3. Установка TCP-соединения: Браузер устанавливает TCP-соединение с сервером, используя полученный IP-адрес и указанный порт (обычно порт 80 для HTTP или 443 для HTTPS). Во время этого этапа происходит процесс, называемый “TCP handshake” (установка соединения по протоколу TCP).
  4. Отправка запроса: Браузер формирует HTTP-запрос, включающий метод запроса (GET, POST и т. д.), путь к ресурсу и другую нужную информацию (например, заголовки запроса) и отправляет этот запрос на сервер по установленному TCP-соединению.
  5. Обработка запроса на сервере: Сервер, получив запрос, обрабатывает его и формирует соответствующий ответ. Это может включать выполнение серверного кода, доступ к базе данных, файловой системе и другим ресурсам.
  6. Передача ответа: Сервер отправляет HTTP-ответ обратно по установленному TCP-соединению.
  7. Обработка ответа в браузере: Браузер принимает ответ от сервера и начинает обрабатывать его. Это может включать парсинг ответа, выполнение JavaScript-кода, загрузку дополнительных ресурсов (таких как изображения, стили и скрипты) и рендеринг страницы.
  8. Рендеринг страницы: Браузер интерпретирует полученный ответ и отображает его в окне браузера, создавая структуру DOM (Document Object Model), применяя CSS-стили и отображая содержимое страницы на экране пользовательского устройства.
308
Q

Что такое фронтенд?

A

Фронтенд - клиентская часть приложения: создание пользовательского интерфейса и взаимодействие с пользователем на веб-сайтах и веб-приложениях. Он фокусируется на том, что видит и использует пользователь.

Задачи фронтенд-разработчиков включают:

  1. Разработка и реализация пользовательского интерфейса: Фронтенд-разработчики создают интерактивные и привлекательные пользовательские интерфейсы, используя языки разметки, такие как HTML (язык гипертекстовой разметки), CSS (язык каскадных таблиц стилей) и JavaScript. Они используют эти языки для создания структуры и визуального представления веб-страницы.
  2. Оптимизация производительности и доступности: Фронтенд-разработчики оптимизируют код и ресурсы веб-страницы или веб-приложения для улучшения загрузки и отзывчивости. Они также обеспечивают доступность для пользователей с ограниченными возможностями, такими как люди с ограниченным зрением или инвалиды.
  3. Разработка и интеграция сценариев: Фронтенд-разработчики используют JavaScript для создания интерактивных функций и рабочих процессов на веб-страницах. Они обрабатывают события, отправляемые пользователем, и взаимодействуют с сервером через AJAX-запросы, чтобы получать данные и обновлять содержимое страницы без ее полной перезагрузки.
  4. Тестирование и отладка: Фронтенд-разработчики выполняют тестирование и отладку пользовательского интерфейса, чтобы убедиться, что все функции работают правильно и интерфейс отображается корректно в разных браузерах и на разных устройствах.
  5. Адаптация под мобильные устройства и отзывчивость: Фронтенд-разработчики создают веб-страницы и веб-приложения, которые адаптируются к различным устройствам и разрешениям экранов, чтобы обеспечить удобство использования на смартфонах, планшетах и других мобильных устройствах.

Общими инструментами и технологиями, используемыми фронтенд-разработчиками, могут быть фреймворки и библиотеки, такие как React, Angular и Vue.js, а также инструменты для сборки и управления зависимостями, такие как Webpack и npm.

309
Q

Отличия event.target и event.currentTarget

A

Стандарт выделяет целых три стадии прохода события:

  1. Событие сначала идёт сверху вниз. Эта стадия называется «стадия перехвата» (capturing stage). Используется за счет третьего аргумента addEventListener elem.addEventListener(“click”, highlightThis, true);
  2. Событие достигло целевого элемента. Это – «стадия цели» (target stage). При наступлении события – элемент, на котором оно произошло, помечается как «целевой» (event.target).
  3. После этого событие начинает всплывать. Это – «стадия всплытия» (bubbling stage). Далее событие двигается от event.target вверх к корню документа, по пути вызывая обработчики, поставленные через on* и addEventListener(…., false)

event.currentTarget (=this) – элемент, на котором в данный момент сработал обработчик (до которого «доплыло» событие). По факту, это элемент на котором висит обработчик addEventListener

310
Q

Как узнать тип данных в JS?

A

Оператор typeof возвращает тип аргумента. Это полезно, когда мы хотим обрабатывать значения различных типов по-разному или просто хотим сделать проверку.

У него есть две синтаксические формы:
Синтаксис оператора: typeof x.
Синтаксис функции: typeof(x).

  1. typeof undefined === "undefined"
  2. typeof boolean === "boolean"
  3. typeof number === "number"
  4. typeof string === "string"
  5. typeof bigint === "bigint"
  6. typeof symbol === "symbol"

Однако:
- typeof null === "object" - Это официально признанная ошибка в typeof, ведущая начало с времён создания JavaScript и сохранённая для совместимости. Конечно, null не является объектом. Это специальное значение с отдельным типом.
- typeof object === "object" - Простая структура, используемая не только для хранения данных, но и для создания других структур, где любая структура создаётся с использованием ключевого слова new: new Object, new Array, new Map (en-US), new Set, new WeakMap, new WeakSet, new Date и множество других структур;
- typeof alert === "function" - возвращает “function”, потому что alert является функцией.
- typeof Math === "object" - Math — это встроенный объект, который предоставляет математические операции и константы.

311
Q

Что за проблема чисел с плавающей точкой?

A

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

console.log(0.1 + 0.2); // Выводит: 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // Выводит: false

Для решения проблемы рекомендуется использовать toFixed(), чтобы сохранить нужную точность.

console.log((0.1 + 0.2).toFixed(1)); // Выводит: “0.30”
console.log(parseFloat((0.1 + 0.2).toFixed(1)) === 0.3); // Выводит: true

312
Q

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

A

toFixed(): Округляет число до заданного количества знаков после запятой и возвращает строку.

let number = 3.14159;
let rounded = number.toFixed(2); // Выводит: “3.14”

313
Q

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

A

toString(): Преобразует число в строку, но если аргументом передать систем исчисления, то число преобразуется в другую систему исчисления

console.log((-10).toString(2)); // Выведет ‘-1010’

Чтобы преобразовать обратно:
let number = parseInt(binaryString, 2); // -10
console.log(number); // Выводит: -10

С помощью parseInt() вы можете преобразовывать строки в числа с разными системами исчисления, указывая соответствующее основание. Обрезает десятичные знаки, если они есть.
console.log(parseInt(‘1.9’)); // 1

314
Q

Как проверить, что число является “конечным” - не Infinity, -Infinity, NaN?

A

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

console.log(isFinite(10)); // Выведет: true
console.log(isFinite(Infinity)); // Выведет: false
console.log(isFinite(-Infinity)); // Выведет: false
console.log(isFinite(NaN)); // Выведет: false

315
Q

Как проверить, что число является NaN?

A

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

console.log(isNaN(NaN)); // Выведет: true
console.log(isNaN(10)); // Выведет: false
console.log(isNaN(“строка”)); // Выведет: true

316
Q

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

A

Метод Number.isInteger() используется для проверки, является ли переданное значение целым числом (без десятичной части). Он возвращает true, если число является целым, и false в противном случае.

console.log(Number.isInteger(10)); // Выведет: true
console.log(Number.isInteger(3.14)); // Выведет: false
console.log(Number.isInteger(-5)); // Выведет: true
console.log(Number.isInteger(0)); // Выведет: true
console.log(Number.isInteger(“10”)); // Выведет: false

Number.isInteger() рассматривает только числовые значения. Если нужно проверить является ли целым числом строка, то можно воспользоваться parseInt(). Значение, возвращаемое parseInt(), будет целым числом (обрежутся знаки после запятой, если они были) или NaN, если в начале строки не найдены цифры, результат можно сравнить с переведенной в число строкой и получить true/false.
console.log(parseInt(“10”)); // Выведет: 10
console.log(parseInt(“3.14”)); // Выведет: 3
console.log(parseInt(“строка”)); // Выведет: NaN

317
Q

Какой метод используется для форматирования числа в локальный формат?

A

Метод Number.prototype.toLocaleString() в JavaScript используется для форматирования числа в локальный формат, основанный на настройках региональных параметров пользователя. Этот метод возвращает строку, представляющую число в формате, соответствующем языку и настройкам пользователя.

const number = 12345.6789;
console.log(number.toLocaleString()); // Выведет: “12,345.679” (в формате локали по умолчанию)
console.log(number.toLocaleString(“en-US”)); // Выведет: “12,345.679” (в формате языка en-US)
console.log(number.toLocaleString(“de-DE”)); // Выведет: “12.345,679” (в формате языка de-DE)

318
Q

Как наиболее быстро преобразовать ‘300px’ в number? Какой метод преобразует строку в число с плавающей точкой?

A

Метод Number.parseFloat() в JavaScript используется для преобразования строки в число с плавающей точкой. Он анализирует переданную строку и возвращает числовое значение, соответствующее начальной части строки, которая является десятичным числом. Если начальная часть строки не содержит десятичного числа, метод возвращает NaN (Not a Number).

let numberString = “300px”;
let number = Number.parseFloat(numberString);
console.log(number); // Выводит: 300

let numberString = “3.14”;
let number = Number.parseFloat(numberString);
console.log(number); // Выводит: 3.14

let notANumberString = “abc”;
let notANumber = Number.parseFloat(notANumberString);
console.log(notANumber); // Выводит: NaN

319
Q

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

A

Метод parseInt() в JavaScript используется для преобразования строки в целое число. Он анализирует переданную строку и пытается преобразовать ее в целое число. Однако parseInt() удаляет десятичные знаки и преобразует только целую часть строки. Вторым аргументом можно написать систему исчисления.

let integerString = “42”;
let integer = parseInt(integerString);
console.log(integer); // Выводит: 42

let hexString = “FF”;
let hexadecimal = parseInt(hexString, 16);
console.log(hexadecimal); // Выводит: 255

let notANumberString = “abc”;
let notANumber = parseInt(notANumberString);
console.log(notANumber); // Выводит: NaN

320
Q

Как сравнить строки в JS?

A

Строки можно сравнивать между собой, для сравнения используется лексикографический порядок. Это означает, что первые символы алфавита считаются меньше последних.
Алгоритм посимвольно сравнивает строки до первого несовпадения, либо пока не закончится одна из строк.
console.log(‘А’ < ‘Я’) // true
console.log(‘Кот’ > ‘Код’) // true
console.log(‘Код’ < ‘Кодер’) // true
console.log(‘Код’ === ‘Код’) // true
Сравнение учитывает регистр букв, если необходимо регистронезависимое сравнение, то обе строки приводятся к верхнему или нижнему регистру с помощью методов toUpperCase или toLowerCase.

321
Q

Можно ли придумать сортировку, основанную на сравнении двух элементов, со сложностью лучше, чем O(NlogN)? К примеру, O(n)?

A

Чтобы ответить на вопрос надо сначала вдуматься, что такое сортировка?
1. Надо отсортировать последовательность , т.е. определить перестановку элементов, применение которой даст отсортированную последовательность
2. Всего из N [различных] элементов можно получить N! перестановок
3. Количество вопросов с ответом да/нет для определения одного из N! вариантов log(N!)
4. Сравнение двух элементов - ответ на вопрос да/нет

Чему равен log(N!)?
log(N!) = log(N * (N - 1) * (N - 2) * … * 2 * 1 = log(N) + log(N - 1) + … + log(N / 2) + … + log(2) + log(1)

Сортировок, основанных на сравнении двух элементов быстрее чем O(NlogN) не существует. Однако возможна сортировка быстрее, если она будет основана не на сравнении двух элементов - поразрядная или сортировка подсчетом.

322
Q

условные свойства объекта
conditional object properties

A

{
…(conditional && { param })
}

Когда условие conditional истинно (truthy), выражение { param } создает объект с одним свойством param, равным значению переменной param. Затем оператор … (spread operator) распространяет этот объект во внешний объект или массив.

Если условие conditional ложно (falsy), выражение { param } вернет пустой объект {}. После применения оператора …, пустой объект не будет иметь никакого эффекта на внешний объект или массив.

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

const condition = true;
const param = “value”;

const obj = {
…(condition && { prop: param })
};
// Если condition === true, то obj будет { prop: “value” }
// Если condition === false, то obj будет пустым объектом {}

323
Q

URLSearchParams

A

URLSearchParams - это встроенный класс в JavaScript, который предоставляет удобные методы для работы с параметрами URL. Он используется для создания, изменения и извлечения параметров запроса в URL.

Основные способы использования URLSearchParams включают:

Создание объекта URLSearchParams из строки запроса:
Вы можете создать новый объект URLSearchParams, передавая ему строку запроса в качестве аргумента конструктора. Это позволяет вам легко извлекать и изменять параметры запроса.

const queryString = ‘param1=value1&param2=value2’;
const params = new URLSearchParams(queryString);

Получение значения параметра:
Вы можете использовать метод get() для получения значения параметра по его имени.

const value = params.get(‘param1’);

Установка значения параметра:
Вы можете использовать метод set() для установки значения параметра по его имени.

params.set(‘param1’, ‘new value’);

Добавление нового параметра:
Вы можете использовать метод append() для добавления нового параметра в объект URLSearchParams.

params.append(‘param3’, ‘value3’);

Удаление параметра:
Вы можете использовать метод delete() для удаления параметра по его имени.

params.delete(‘param2’);

Получение строки запроса:
Вы можете использовать метод toString() для получения строки запроса, содержащей все параметры объекта URLSearchParams.

const queryString = params.toString();

URLSearchParams особенно полезен при работе с параметрами URL, такими как параметры запроса в адресной строке браузера или параметры, используемые при отправке HTTP-запросов. Он предоставляет удобные методы для манипуляции параметрами и облегчает чтение и изменение URL-строки.

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

const params = new URLSearchParams();
params.append(‘param1’, ‘value1’);
params.append(‘param2’, ‘value2’);

console.log(params.toString()); // выводит: “param1=value1&param2=value2”

params.set(‘param1’, ‘new value’);
params.delete(‘param2’);

console.log(params.toString()); // выводит: “param1=new%20value”

В этом примере мы создаем новый объект URLSearchParams, добавляем несколько параметров, затем изменяем и удаляем некоторые из них, и наконец, выводим строку запроса с помощью метода toString().