JS Flashcards

1
Q

Назовите 3 любых метода функции

A

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

  1. f.length - сколько аргументов принимает функция
  2. f.bind - переводится, как связывать. То есть этот метод позволяет связать объект person с ключевым словом this во внешней функции через вспомогательную функцию.

const person = { // объект
firstname: ‘James’,
lastname: ‘Murray’,
showFullName: function(){
return this.firstname + ‘ ‘ + this.lastname;
}
}
function getSkills(s1, s2){ // функция, которую хотим связать с объектом
console.log(this.showFullName() +’ has skills: ‘+s1+’, ‘+s2);
}

let personSkills = getSkills.bind(person);
//Вызываем метод bind у копии нашей функции, где аргумент будет объект. Теперь personSkills - новая функция, которая при вызове устанавливает в качестве контекста выполнения this предоставленное значение.
personSkills(‘HTML/CSS’, ‘JavaScript’);
// Вызываем новую функцию, теперь в функции getSkills, this - объект person

//или 2-м способом, указав параметры вызова функции сразу
let personSkills = getSkills.bind(person, ‘HTML/CSS’, ‘JavaScript’);
personSkills();

// Можно так же связать другой this c копией функции:
const newObj = { firstname: ‘Tim’,
lastname: ‘Tock’,
showFullName: function(){
return this.firstname + ‘ ‘ + this.lastname;
}}
let personSkills2 = getSkills.bind(newObj );
// создали новую функцию и передали другой объект
personSkills2 (‘React\Redux’, ‘TypeScript’);

// this присваивается один раз, по этому мы не можем переприсваивать дальше с помощью bind его. Это касается одной и той же функции, например, personSkills . Мы не можем вот так по цепочке переприсвоить -
let personSkills = getSkills.bind(person).bind(person2).bind(person3)

  1. f.call - Отличием метода call() от bind() является то, что нет необходимости создавать вспомогательную функцию для того, чтобы передать в качестве this нужный объект.
    Метод call() вызывает функцию с указанным значением this и индивидуально предоставленными аргументами.

getSkills.call(person, ‘PHP’, ‘Python’); //James Murray has skills: PHP, Python
// мы вызвали у нашей функции метод call, передали объект-person в качестве this и два аргумента, которые принимает наша функция.
В отличие от bind(), call() не копирует функцию. Он позволяет передавать объект в качестве this и любые аргументы, а затем немедленно вызывает функцию.

  1. f.apply - Методы apply() и call() практически идентичны при работе с выставлением значения this, за исключением того, что передаём параметры функции в apply() как массив, в то время, как в call(), параметры передаются в индивидуальном порядке.
    getSkills.apply(person, [‘C++’, ‘C#’]); //James Murray has skills: C++, C#
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Что такое рекурсия?

A

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

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

чем отличает == от ===?

A

Оператор == сравнивает на равенство, а вот === — на идентичность.
Тройное равенство не приводит два значения к одному типу.

false == 0 - true /псевдоложь (‘‘,0,false,[])
true == 1 - true

false ===0 - false / не идентичны типы
true == 1 - false

При сравнении строки с числом, JS попытается строку преобразовать в число - ‘01’ == 1 - true (1==1)

Boolean - проверяет на булевое знаяение:
let a = 0; - 0=false
alert( Boolean(a) ); // false

let b = “0”; - “0”-непустая строка = true
alert( Boolean(b) ); // true

alert(a == b); // true! - JS попытается преобразовать строку в число, а значит 0==0 - true. При строгом равенстве будет false, тк разные типы данных.

null == undefined - true
null === undefined - false

При использовании математических операторов и других операторов сравнения < > <= >=: значения null/undefined преобразуются к числам: null становится 0, а undefined – NaN.

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

Зачем нужен и у кого он есть метод addEventListener?

A

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

Есть метод onClick, он позволяет повесить обработчик события, если мы попытаемся повесить второй обработчик с таким же событием на элемент, то у элемента теперь будет более новый обработчик события. Таким образом, onClick позволяет повесить только один обработчик на событие.
Метод addEventListener позволяет добавлять несколько обработчиков на одно событие одного элемента, например:

function handler1() {
alert(‘Спасибо!’);
};
function handler2() {
alert(‘Спасибо ещё раз!’);
}

elem.onclick = () => alert(“Привет”);

elem.addEventListener(“click”, handler1); // Спасибо!

elem.addEventListener(“click”, handler2); // Спасибо ещё раз!

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

👇
Хорошим тоном считается убирать обработчик сразу же, как он перестал быть нужен.

Всегда сохраняйте функцию-обработчик в переменную чтобы позже убрать обработчик. !!!!!

const handleMouseClick = (event) =>{
//обязательно в переменную или если это функция - Function Declaration, то в removeEventListener записываем имя функции, как и переменную
console.log(‘Вы нажали на элемент:’, event.target)
}

window.addEventListener(‘click’, handleMouseClick, true)

// Ничего не передаем в опциях в третьем аргументе
window.removeEventListener(‘click’, handleMouseClick)

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

Что такое NodeJS?

A

Node.js — не отдельный язык программирования, а платформа для использования JavaScript на стороне сервера для веб-страниц и веб-приложений, а также для программ командной строки.

С помощью Node.js реализуется парадигма «JavaScript для всего». Она предполагает использование одного языка программирования для разработки веб-приложений вместо применения разных языков для работы над фронтендом и бэкендом.

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

Имеет пакетный менеджер NPM, который содержит множество библиотек.

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

Что такое замовызывающаяся функция?

A

Обычно она не имеет названия:
(просто засунули в переменную, чтобы получить результат из return)

const data = (function(){
let a = 100
let b = 90
})()

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

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

Расшифруйте аббревиатуру БЭМ

A

Это методология, разработал Яндекс.
БЭМ (Блок, Элемент, Модификатор) — компонентный подход к веб-разработке. Принцип - разделение интерфейса на независимые блоки.
Он позволяет легко и быстро разрабатывать интерфейсы любой сложности и повторно использовать существующий код, избегая «Copy-Paste».

Блок - Функционально независимый компонент страницы, который может быть повторно использован. В HTML блоки представлены атрибутом class.
Название блока характеризует смысл («что это?» — «меню»: menu, «кнопка»: button)

Элемент - Составная часть блока, которая не может использоваться в отрыве от него.
Название элемента характеризует смысл («что это?» — «пункт»: item, «текст»: text)
Элемент — всегда часть блока, а не другого элемента. Это означает, что в названии элементов нельзя прописывать иерархию вида block__elem1__elem2. Только block__elem1 и block__elem2

Модификатор - Cущность, определяющая внешний вид, состояние или поведение блока либо элемента.
Название модификатора характеризует внешний вид («какой размер?», «какая тема?»
состояние («чем отличается от прочих?» — «отключен» и поведение («как ведет себя?», «как взаимодействует с пользователем?» — «направление»

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

Согласно принципу REST API задокументируй еndPoint , удаляющий конкретный репозиторий конкретного пользователя

A

Мы должны знать куда слать - это URL,
какой тип запроса - type,
что в ответе будет - response: статус запроса - status

  1. Какой URL у нас будет:
    ‘<базовый>/users/:id/repozitories/rep-:id'
    Сначала базовый url, потом список юзеров, потом находим определенного юзера по id, затем заходим в список его репозиториев и затем удаляем по id конкретный репозиторий.</базовый>
  2. Хотим удалить этот репозиторий, значит нам нужно знать какой тип type (http методы) - DELETE
  3. status может вернуться 200 - если удаление произошло, точнее 204 - нет содержимого для ответа на запрос, но заголовки ответа, которые могут быть полезны, присылаются., тк мы удалили репозиторий.
    Или если нет прав доступа к серверу, чтобы удалить - 403

Дополнительно:
POST(создать новый репозиторий)-‘<базовый>/users/:id/repozitories/'
Сначала базовый url, потом список юзеров, потом находим определенного юзера по id, затем заходим в список его репозиториев и уже создаем новый репозиторий</базовый>

GET(получить конкретный репозиторий) - ‘<базовый>/users/:id/repozitories/rep-:id'</базовый>

Маршрут (Route - роут) — это «имя», которое отсылает работу API к определенным эндпоинтам. Если упростить, то можно сказать, что маршрут - это URL к которому можно обратиться разными HTTP методами. Маршрут может иметь несколько эндпоинтов.

Эндпоинт (Endpoint - конечная точка) — это само обращение к маршруту отдельным HTTP методом. Эндпоинт выполняют конкретную задачу, принимают параметры и возвращают данные Клиенту.

http://example.com/wp-json/wp/v2/posts/123:

Здесь wp/v2/posts/123 — это маршрут, а /wp-json — это базовый путь самого REST API.
Этот маршрут имеет 3 эндпоинта:
GET — запускает метод get_item() и возвращает данные поста Клиенту.
PUT|PATCH|POST — запускает метод update_item(), обновляет данные и возвращает их Клиенту.
DELETE — запускает метод delete_item(), удаляет пост и возвращает только что удаленные данные Клиенту.

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

Найти отличие между HTTP1 и HTTP2

A

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

1.Способ упаковки:

  1. Cпособ передачи запроса и ответа:
    HTTP2 может организовать в рамках одного соединения с сервером параллельно обмен несколькими сообщениями(так называемые стримы).
    Называется этот параллельный обмен сообщениями в рамках одного подключения - Мультиплексирование.
    В HTTP1 нет многопоточности, необходимо было ждать.
    Раньше нужно было на сервере склеивать в один js-файл другие js-файлы(аналогично и с картинками, склеивали в большой спрайт) для того, чтобы фронтенд запрашивал один этот файл. Если бы не склеивали, то пришлось бы запрашивать каждый раз по отдельности эти js-файлы,при этом соединение каждый раз открывается\закрывается. Плюс браузер ограничивает одновременное количество запросов к одному домену.
    Оч много времени тратилось на обмен данными.

https://habr.com/ru/articles/739166/
В чем отличия HTTP1, HTTP2 , HTTP3

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

Что такое DNS и как он работает?

A

DNS (Domain name system) — это система, которая позволяет писать человекопонятным языком названия сайтов(incubator.ru - доменное имя) в поисковую строку браузера, а браузеру находить нужный сайт и отображать его.

DNS занимается тем, что преобразует названия сайтов — доменные имена(incubator.ru), которые вводят в поисковую строку браузера в IP-адреса конкретных серверов. Если бы не было DNS, вам бы пришлось запоминать IP-адреса нужных вам ресурсов и вводить их вручную в браузер.

Сведения о доменах(incubator.ru) и их связи с IP-адресами находятся в распределенной базе данных, которая хранится на DNS-серверах, образующих иерархию.

Когда вы вводите запрос в поисковую строку браузера, например, 1cloud.ru — браузер сначала проверит наличие DNS-записи на вашем локальном компьютере в файле hosts, если там нет нужного адреса, запрос направляется дальше — на локальный DNS-сервер интернет-провайдера пользователя, если и там записи нет, запрос уходит выше на сервера географических зон.

Как только нужная DNS-запись найдена, браузер получает IP-адрес, на который посылает запрос. В ответ приходит web-страница.

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

Локальный DNS-сервер(локальное хранилище) опрашивает DNS-сервера второго, верхнего и корневого уровней, а не браузер! Он находит сведения о домене, возвращает их браузеру и записывает данные в кеш на 24 часа. В итоге при следующем обращении к этому сайту, он просто вернет данные из кеша и сайт загрузится быстрее.

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

Что такое CDN (Content Delivery Network)?

A

это группа особым образом настроенных серверов, расположенных в разных геоточках. Серверы выступают в качестве узлов, которые позволяют быстро загружать контент ближайшим пользователям.
Таким образом, разветвленная сеть CDN с расположенными неподалеку серверами позволяет значительно сократить время загрузки удаленных сайтов.
То есть, когда на московский сайт заходит посетитель из Сахалина или Хабаровска, то контент будет загружаться не из Москвы, а из Владивостока. Естественно, это положительно скажется на скорости загрузки сайта.

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

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

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

Что такое Event Loop?

A

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

Общий алгоритм движка:
-Пока есть задачи: выполнить их, начиная с самой старой.
-Бездействовать до появления новой задачи, а затем перейти к пункту 1.
Задачи поступают на выполнение – движок выполняет их – затем ожидает новые задачи (во время ожидания практически не нагружая процессор компьютера).

Может так случиться, что задача поступает, когда движок занят чем-то другим, тогда она ставится в очередь.
Очередь, которую формируют такие задачи, называют «очередью макрозадач» .
Макрозадачи - setTimeout, eventListener и т.д.
Например, когда движок занят выполнением скрипта-

, пользователь может передвинуть мышь, тем самым вызвав появление события mousemove, или может истечь таймер, установленный setTimeout, и т.п. Эти задачи формируют очередь.
Задачи из очереди исполняются по правилу «первым пришёл – первым ушёл». Когда браузер заканчивает выполнение скрипта, он обрабатывает событие mousemove, затем выполняет обработчик, заданный setTimeout, и так далее.

Пример, подсветка синтаксиса - трудоемкая задача для движка, особенно, если текста много. Пока он занят выполнением, то он не сможет обрабатывать пользовательские события, связанные с DOM.
Т.е. пользователь нажмет на кнопку, но ничего не произойдет, будет подвисание, тк движок продолжает обрабатывать старую задачу.
Избежать этого поможет setTimeout, таким образом разобьем задачу на несколько простых. Например, задать подсветку для первых сто страниц, а затем запланировать setTimeout с нулевой задержкой для разметки следующих сто страниц. Если произойдет пользовательские событие, то оно встанет в очередь после задачи с первыми сто страницами и выполнится по ее завершению, затем будет выполнятся следующие сто страниц.
Дополнительно: помним, в браузере есть минимальная задержка в 4 миллисекунды при множестве вложенных вызовов setTimeout. Даже если мы указываем задержку 0, на самом деле она будет равна 4 мс (или чуть больше). Поэтому чем раньше мы запланируем выполнение – тем быстрее выполнится код.

Микрозадачи:
Микрозадачи приходят только из кода. Обычно они создаются промисами: выполнение обработчика .then/catch/finally становится микрозадачей. Микрозадачи также используются «под капотом» await, т.к. это форма обработки промиса.

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

Все микрозадачи завершаются до обработки каких-либо событий или очереди рендеринга, или перехода к другой макрозадаче.

Например:

setTimeout(() => alert(“timeout”)); - 3 т.к. макрозадача

Promise.resolve()
.then(() => alert(“promise”)); -2 . т.к. здесь .then

alert(“code”); - 1 т.к. синхронный код

Какой здесь будет порядок?
-code появляется первым, т.к. это обычный синхронный вызов.
-promise появляется вторым, потому что .then проходит через очередь микрозадач и выполняется после текущего синхронного кода.
-timeout появляется последним, потому что это макрозадача.

Итого: полный алгоритм

1.Выбрать и исполнить старейшую задачу из очереди мАкрозадач (например, «script»).
Принцип - первый зашел-первый вышел.

  1. Исполнить все мИкрозадачи:
    Пока очередь микрозадач не пуста: - Выбрать из очереди и исполнить старейшую микрозадачу(Принцип - первый зашел-первый вышел.)
  2. Отрисовать изменения страницы, если они есть.
  3. Если очередь макрозадач пуста – подождать,
    пока появится макрозадача.
  4. Перейти к шагу 1.

Так же есть еще одна очередь помимо макро и микрозадач, это очередь рендера, она состоит из
–requestAnimationFrame
–style
–layot
–paint
–composite
На этих этапах браузер пересчитывает стили, как расположить элементы, их размеры, применение цвета, фона и т.д.

Если сравнивать очередь макрозадач и очередь рендера, то в приоритете будет очередь рендера, например:
очередь макро | очередь рендера
макро2 | рендер 2
макро1 | рендер 1
Если после макро1 собралась очередь из рендера, то они(рендер 1 и рендер 2) выполнятся ПЕРЕД макро2. Если же в момент выполнения очереди рендера присоединится еще один - рендер3, то он уже будет выполнятся после выполнения макро2, НО перед выполнением макро3, если такая появится.

Приоритеты:
1 - микротаски, выполняется вся очередь микротасок перед выполнением макротаски и очереди рендера. Если вовремя выполнения микротасок приходят еще, то они продолжатся выполнятся, пока очередь не опустошится.
2 - очередь рендера, выполняются перед макротасками и после выполнения всей очередь микротасок. Если во время выполнения этой очереди приходят еще новые рендеры, то они откладываются на следующее выполнение перед следующей макротаской.
3 - очередь макротасок.
Важно!!! Если приходит синхронная операция, то она прерывает все очереди и выполнится в Стеке вызова мгновенно, даже если в это время выполнялась очередь микротасок.
Создание промиса - new Promise - та же синхронная операция, а уже обработка промиса, например, .then - это уже ассинхронщина(микротаска)

Такой цикл состоит из:
–Call Stack(стек вызовов), где действует правило “Первый зашел-первый вышел”. Туда попадают синхронные операции.
–Queue(очередь), куда попадают ассинхронные операции, там выполняются. И далее=>
–Callback queue(очередь обратного вызова), куда попадают выполненные ассинхронные операции и ждут свой очереди, пока все синхронные операции не уйдут и Call Stack не очистится, чтобы попасть в Call Stack, отработать и выйти оттуда.

Пример1: здесь рассм-ся с ассинх. операциями
console.log(‘a’) - зашел-вышел
setTimeout(()=>console.log(‘d’)) -попал в Queue
console.log(‘b’) - зашел-вышел
console.log(‘c’) - зашел-вышел

Пример2: здесь синхронные операции
function a(){} - пятый зашел и вышел
function b(){ a() }- четвертый зашел и остался
function c(){ b() }- третий зашел и остался
function d(){ c() } - второй зашел и остался
function e(){ d() } - первый зашел и остался
e()
Call Stack будет таким:
function a() последний зашел-первый вышел
function b()
function c()
function d()
function e() первый зашел-последний вышел =>
Почему? Потому что для выполнения ему необходимо дождаться выполнение функции d() и т.д. для выполнения функции d() необходимо выполнение функции c()

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

Что такое git?

A

Git — это система контроля версиями.
Git позволяет разработчикам создавать репозитории, в которых хранятся файлы проекта и история их изменений.

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

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

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

Чем отличается localStorage от sessionStorage?

A

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

Local Storage - даже после перезапуска браузера (до ручной очистки данных браузера или до установленной даты)
Пример: токен пользователя

Session Storage -сохраняются после обновления страницы, но не после закрытия/открытия вкладки. Существует только в рамках текущей вкладки браузера. Другая вкладка с той же страницей будет иметь другое хранилище.
Пример может быть банковские транзакции, пополнение форм

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

Чем отличается Function Declaration от Function expression?

A

Во-первых, синтаксис: как отличить их друг от друга в коде.

Function Declaration: функция объявляется отдельной конструкцией «function…» в основном потоке кода.
Function Expression: функция, созданная внутри другого выражения или синтаксической конструкции. В данном случае функция создаётся в правой части «выражения присваивания» =:

Function Expression(функ.выражение) создаётся, когда выполнение доходит до него, и затем уже может использоваться.
После того, как поток выполнения достигнет правой части выражения присваивания let sum = function… – с этого момента, функция считается созданной и может быть использована (присвоена переменной, вызвана и т.д. ).

Function Declaration может быть вызвана раньше, чем она объявлена.
Другими словами, когда движок JavaScript готовится выполнять скрипт или блок кода, прежде всего он ищет в нём Function Declaration и создаёт все такие функции. Можно считать этот процесс «стадией инициализации».
И только после того, как все объявления Function Declaration будут обработаны, продолжится выполнение.
В результате функции, созданные как Function Declaration, могут быть вызваны раньше своих определений.

Речь идет о “всплытии” (hoisting):

При использовании Function Declaration, объявление функции поднимается вверх текущего контекста выполнения кода.
Это означает, что функцию можно вызывать до того, как она фактически была объявлена в коде.
example();
// Работает, потому что Function Declaration поднимается вверх
function example() {
console.log(“Hello, World!”);
}

В случае Function Expression, переменная example поднимается вверх, но само присваивание (и объявление функции) остается на месте в коде. Поэтому, если вы попытаетесь вызвать функцию до строки с присваиванием, вы получите ошибку.
// Не работает, потому что присваивание (и объявление функции) ещё не произошло
example();
var example = function() {
console.log(“Hello, World!”);
};

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

typeof NaN
typeof undefined
typeof null
typeof Bigint
typeof []
typeof Function(){}
оператор “нулевого слияния” (??)

A

typeof NaN = number / сравниваем NaN = NaN только через isNaN(NaN)

typeof undefined = undefined

typeof null = object

typeof Bigint = bigint

typeof [] = object

typeof Function(){} = function

оператор “нулевого слияния” (??), который позволяет выбрать первое из определенных значений (не равных null или undefined).
var myValue = null;
var result = myValue ?? “default”;
console.log(result); // “default”

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

Методы строк?

A

.toUpperCase()
.toLowerCase()
.length
str.indexOf(substr, pos) - ищет подстроку substr в строке str, начиная с позиции pos, и возвращает позицию, на которой располагается совпадение, либо -1 при отсутствии совпадений.
str.lastIndexOf(substr, position), который ищет с конца строки к её началу
str.includes(substr, pos) возвращает true, если в строке str есть подстрока substr, либо false, если нет.
str.startsWith(substr) и str.endsWith(substr) проверяют, соответственно, начинается ли и заканчивается ли строка определённой строкой
str.slice(start [, end]) - возвращает часть строки от start до (не включая) end.
.split - на массив

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

Что такое семантические теги?
Что такое семантические элементы?
Что такое не семантические элементы?

A

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

<header> <nav> <footer> <aside>

Что такое семантические элементы?
<form>, <table> и <article> – это семантические элементы: они четко определяют свое содержание.

Что такое не семантические элементы?
<div> и <span> являются не семантическими элементами. Они ничего не говорят нам об их содержании.

Теги помогают быстрее обрабатывать код поисковым роботам, вследствие чего у вашего сайта больше шансов попасть на первые страницы Google, Yandex и т.д.
</span></div></article></table></form></aside></footer></nav></header>

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

В чем разница протоколов HTTP и HTTPS?
И еще - вообще для чего нужен https , если на сайте не требуется вводить какие-то личные данные и тп?

A

«HTTP, или Hyper Text Transfer Protocol, — это протокол передачи гипертекстовой разметки(HTML), которая используется для передачи данных в интернете».

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

(гипертекстовоя разметка - это HTML(HyperText Markup Language) ), язык гипертекстовой разметки текста. Он нужен, чтобы размещать на веб-странице элементы: текст, картинки, таблицы и видео. HTML как бы выстраивает визуальный фундамент сайта)

Когда мы набрали запрос и нажали ввод, браузер отправил этот запрос на веб-сервер.На веб-сервере хранятся статьи в виде картинок, HTML-документов, файлов с CSS-стилями и JavaScript-файлами. Также на веб-сервере установлено ПО, которое понимает HTTP-протокол.
Веб-сервер принимает запрос, обрабатывает, определяет, какие файлы отправить, и отдает их в ответ. Браузер принимает эти данные, интерпретирует и показывает нам в «человеческом» виде.
Каждое действие в блоге, например, переход по ссылке на статью, — это новый запрос серверу и новый ответ.

HTTPS — это не совсем протокол. Это расширение HTTP-протокола — объединение двух протоколов: HTTP и TLS.
Протокол TLS (Transport Layer Security) — криптографический. Это значит, что они позволяют шифровать данные, в нашем случае те, что передаются между браузером и сервером. Расшифровать эти данные могут только сервер и браузер, для всех остальных это будет набор нечитаемых символов.

Как работает шифрование:

У ресурса/сайта, поддерживающего HTTPS, есть TLS-сертификат, который выдается центром сертификации. Если у ресурса в адресной строке есть зеленый замок, соединение с ним защищено.
Посмотреть информацию о сертификате и его подлинности можно, нажав на значок.

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

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

Если все хорошо, то браузер считает ресурс безопасным: они выбирают алгоритм шифрования, обмениваются ключом шифрования и потом данными по протоколу HTTP.

Сейчас в браузерах работает HSTS — HTTP Strict Transport Security. Это защитный механизм браузера, который принудительно переводит соединение из HTTP в HTTPS или обрывает HTTP-соединение.
Чаще всего ресурс на HTTP браузер просто не откроет, а выведет предупреждение. Например, в браузере Google Chrome незащищенные ресурсы блокируются еще с 2020 года.
Стандарт задают поисковики и веб-браузеры. Сейчас без зеленого значка у сайта в адресной строке к ресурсу не будет доверия у пользователей, если он вообще откроется в браузере. Поисковики настоятельно рекомендуют переходить на HTTPS. Например, Яндекс открыто сообщает о том, что сайты, не использующие сертификаты, будут ниже в поисковой выдаче.

И еще - вообще для чего нужен https , если на сайте не требуется вводить какие-то личные данные и тп?
Для того, чтобы в response-в ответ от сервера не дополнили какими-то неправильными данными.Например, реклама

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

Что такое WebSoket?

A

Это протокол.

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

Какие протоколы бывают :
HTTP, HTTPS
WebSoket, WWS
FTP,«File Transfer Protocol»позволяют пересылать файлы с одного устройства (например, компьютера Mac, Windows или Linux ) на другое.
SMTP, Simple Mail Transfer Protocol простой протокол связи, применяемый с целью пересылки электронных писем с сервера отправителя на сервер получателя.
POP3 Post Office Protocol почтовый протокол, с помощью которого загружаются сообщения на почтовый клиент с удаленного сервера.

Пишется протокол в адресной строке вначале доменного имени.
Зачему нужны разные протоколы? Разные программы взаимодействуют между собой через разные протоколы.

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

WebSoket: Реактивно реагирует что происходит на сервере. Сервер тоже отправляет запросы клиенту. У HTTP тоже есть по аналогии, но WebSoket популярнее.

Как это работает?
Клиент создает канал к серверу и по этому каналу могут оба они делают запросы-реквесты друг другу. Например, нам отправляют личное сообщение, сервер это увидел и по каналу мгновенно отправляет его нам.

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

try catch finally

A

try - выполняется код
catch - если в процессе выполнения кода возникнет ошибка, то попадем сюда. Здесь мы можем как-то проанализировать ошибку.
finally - если нет ошибок , то попадаем сюда
И далее уже вниз идем по коду дальше.

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

Но в некоторых случаях finally нужен, например сёркл(крутилка при загрузки), если нет ошибок, то ее нужно убрать, если возникнет ошибка, ее так же нужно убрать. То есть если возникнет ошибка, то мы в код ниже не попадем, а нам нужно убрать крутилку. По этому finally и нужен.

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

Для чего нужен Promise.all?

A

Promise.all([промис, промис, промис])

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

.all - это метода класса промис, принимает массив промисов, вернет метод промис тогда, когда все промисы заресолвятся(resolve-выполнится тогда, когда завершилось успешно и получили результат, противоположно этому - rejected)
Передаем массив других промисов

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

Назовите минимум 3 метода жизненного цикла классовой компоненты?

A

Каждый компонент React проходит несколько стадий в процессе своей жизни:
он создается,
затем добавляется в DOM,
получает пропсы,
и, наконец, удаляется из дерева.
Этот процесс называют жизненным циклом компонента (Component Lifecycle).
React предоставляет набор методов, которые позволяют встроиться в этот процесс. Например, запуск часов логичнее всего сделать сразу после их отрисовки.

1 этап: Монтирование (Mounting):
Появление в HTML\рождение компоненты.
Если компонента отрисовалась\появилась в DOM, то произошел этот цикл.

Эти методы вызываются по порядку во время создания объекта и вставки его в DOM.
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()

Как мы можем написать функцию, чтобы она сработала сразу же после рождения компоненты?
Можно использовать useEffect().
useEffect(()=>{ }, [ ]) - первый аргумент - коллбэк, который сработает, второй аргумент - зависимость, если он пустой, то наш коллбэк сработает 1 раз при рождении компоненты.
Что как правило происходит на стадии рождения?
Общение с бэкендом - если мы хотим сделать запрос на бэкенд, взять какие-то данные, например, список пользователей. Это самое лучше, что может происходить при рождении компоненты. Происходит это в useEffect().

2 этап: Обновление\появление (Updating)

Обновление может происходить при изменении свойств или состояния. Эти методы вызываются по порядку во время перерисовки:
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()

Что заставляет компоненту обновляться?
Изменение пропсов и изменение стейта.
Здесь опять же помогает это отследить useEffect().
useEffect(()=>{ }, [ ]) - первый аргумент - коллбэк, который сработает, если произошли изменения, второй аргумент - зависимость, там лежит стейт\пропсы, которые будут отслеживаться, произошли ли в них изменения, если да, то выполнится коллбэк. Если приходящие пропсы изменились, то произойдет перерисовка.
Внимание, этот useEffect первый раз вызовется при рождении компоненты, и далее будет вызываться тогда, когда произойдут изменения в стейте!

3 этап: Удаление или демонтирование (Unmounting)

Он вызывается во время удаления компонента из DOM.
Один метод:
componentWillUnmount()

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

useEffect(() => {
// код подписки на ресурс
unmountBtn.addEventListener(“click”, unmount);
return () => {
// код отписки от ресурса
unmountBtn.removeEventListener(“click”, unmount);
};
});

В начале функции хука идет подписка на ресурс, а далее оператор return возвращает функцию, которая выполняет отписку от ресурса.

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

Что такое PWA?

A

«Progressive Web Application» — прогрессивное веб-приложение.

Технология в web-разработке, которая визуально и функционально трансформирует сайт в приложение (мобильное приложение в браузере)»
По сути, это «прокачанная» копия веб-сайта, размещенная на устройстве пользователя и не требующая отдельной разработки для iOS или Android.

PWA — это сайты с расширенной функциональностью, которая позволяет им быть похожими на нативные мобильные приложения.

Работают эти приложения так же, как и обычные мобильные приложения: показывают Push-уведомления, работают в автономном офлайн-режиме, сохраняют данные локально. По внешнему виду они ничем не отличаются от нативных приложений и могут размещать иконку на рабочем столе (домашнем экране) для быстрого запуска.

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

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

Все ли в js объекты?

A

Примитивы – не объекты.
У примитивов, кроме null и undefined, есть свои методы, но они не объекты.

Чтобы методы работали, при таком доступе создаётся специальный «объект-обёртка», который предоставляет нужную функциональность, а после удаляется.

array, object, function - это все объекты
Но при проверки через typeof function - это будет Function.

Так же при проверке через typeof null покажет Object, но это примитив. typeof null, дающее ‘object’, было ошибкой в ранней реализации JavaScript.
null показывает отсутствие какого-либо объектного значения.

Если вы видите null (присвоенное переменной или возвращенное функцией), то в этом месте должен быть объект, но по какой-то причине объект не был создан.

Не используйте оператор typeof для определения значения null. Как упоминалось ранее, используйте оператор строгого равенства myVar === null.

Пример:
// переменная foo существует, но она не имеет ни типа, ни значения:
> var foo = null; - переменная существует - это foo
// переменная foo не существует - она не была определена и никогда не инициализировалась:
> foo - undefined

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

Зачем нуден async/await?

A

Это синтаксический сахар над тем что уже есть.
Это нужно для работы с ассинхронным кодом.
В js есть удобная штука для работы с таким кодом -Promise. Это объект, который может находится в одном из трех состояний -
1.pending(ожидает, если результат еще не готов, ожиданиет завершения каких-то ассинхр.операций),
2.resolved(завершение, результат доступен, что-то завершилось сове выполнение, все прошло хорошо),
3.rejected(произошла ошибка в процессе выполнения, отклонен)

Как мы одного из трех состояний дожидаемся?

с помощью .then, т.е. чтобы получить ответ и его обработать, мы будем использовать цепочку then-ов:
promise.then( (response)=> … ).then((data)=> … )

Зачем нужен async/await?
Дожидание , когда промис зарезолвится(resolved), те мы с помощью await дожидаемся когда промис зарезолвится, а это ожидание может происходить только в ассинхр.функции - async.

Такой код выглядит короче, без этих вложенностей с коллбэками, нам не нужно использовать .then, теперь пишем так:
(async () => {

let response = await fetch(‘/article/promise-chaining/user.json’);
//получили промис
//если fetch не выполнится, то код ниже него не будет выполнятся

let user = await response.json();
//обработали в json

})(); -async/await всегда возвращает промис, так же необходимо такой код заворачивать в async , в данном случае можно обернуть анонимной самовызывающейся функцией.
Так же проще делать обработчку ошибок try\catch

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

Функция – это какой тип?

A

В JavaScript функции – это объекты. Значит это ссылочный тип данных.
Функции можно не только вызывать, но и использовать их как обычные объекты: добавлять/удалять свойства, передавать их по ссылке и т.д.

  1. Имя функции - методом .name
    function sayHi() {
    alert(“Hi”);
    }
    alert(sayHi.name); // sayHi

2.Метод «length» содержит количество параметров функции в её объявлении.
function f2(a, b) {}
alert(f2.length); // 2 - длина рассчитывается по количеству параметров
function many(a, b, …more) {}
alert(many.length); // 2 - rest-оператор не считается

3.Мы также можем добавить свои собственные свойства.
function sayHi() {
alert(“Hi”);

sayHi.counter++; // добавили свойство .counter
}

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

Что такое кэш?

A

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

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

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

Кэш можно почистить в инструментах разработчика. Заходим в раздел Приложение =>
Хранилище => Удалить данные сайта

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

Что такое куки?

A

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

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

Примеры:

1.Авторизация на сайте. Как известно большинство сайтов имеют авторизацию (ввод пароля, логина, телефона, почты и т. п.). Cookie могут применяться сервером для опознания ранее аутентифицированных пользователей.

  1. Корзина в интернет-магазинах. Если не использовать куки, при выборе товара и переходе на новую страницу товар может исчезнуть.
  2. Настройки. К примеру, мы выставили нужные настройки региона, языка и т. д. Без куки они могут сброситься и вернуться в статус значений по умолчанию.

Куки можно почистить в инструментах разработчика.
В приложение =>
То есть надо будет выбрать адрес сайта под строкой Cookie, нажать правую кнопку мыши, а потом «Clear».

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

Что такое SPA?

A

Браузер делает запрос на сервер, он отправляет один файл index.html и bundle.js
(В большинстве проектов собирают все javascript файлы (а иногда css и картинки тоже) в один очень большой bundle.js.(Сборщик модулей WebPack создает этот файл, собирая все файлы в единый файл). Сreate-react-app использует под капотом webpack со всеми необходимыми плагинами.)

После этого кликая по ссылкам в приложении, мы уже не заправшиваем у сервера новый HTML-файл и js-файл, можем запрашивать только какие-то API-данные в формате json или xml . Реакт сам рисует компоненты, которые необходимо отобразить.
Благодаря Реакт-роутеру, мы сможем отображать эти переходы к другим компонентам, вместо того, чтобы отправлять запрос на сервер.

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

Что такое DOM?

A

Браузер не работает с HTML-страницей напрямую как с текстом, а строит для этого DOM.!!!!!!!!!!!!!!!!!!!!

Document Object Model - это объектная модель документа , представляет собой древовидную структуру страницы, состоящую из узлов. Каждый узел в ней – это объект, который может иметь определённые свойства и методы. DOM-узлы образуются из всего, что есть в HTML: тегов, текстового контента, комментариев и т.д. Эти объекты связанным между собой иерархически, те родитель-ребенок и тд.

Корневым узлом DOM-дерева является объект document - входная точка в DOM: document=>html=> разделяется на: head и body => и т.д.

Каждый узел в DOM – это объект, который может иметь определённые свойства и методы.
На свойства часто ссылаются как на то, с чем необходимо что-либо сделать (например, название узла). document.innerHTML - отобразит текст, который содержится в элементе html.
На методы часто ссылаются как на то, что необходимо сделать (например, удалить узел):
document.getElementById(id) - получить элемент с указанным id из всего html
document.getElementsByTagName(имя) - получить все элементы с указанным названием (именем) тега из всего html
document.appendChild(узел) - вставить дочерний узел в html
document.removeChild(узел) - удалить дочерний узел из html

Формируют древовидную структуру ТОЛЬКО узлы-элементы-теги, текстовые узлы не могут в себе содержать другие узлы и строить дальше дерево!!!

Процесс формирования DOM происходит так: браузер получает HTML-код, парсит его и строит DOM.

Конечной целью является построения отображения этой страницы на экране. Т.е. по сути мы видим ДОМ в браузере.

Основные этапы работ, которые браузер выполняет для преобразования исходного кода HTML-документа в отображение стилизованной и интерактивной картинки на экране. Кстати, этот процесс называется «Критический путь рендеринга» Critical Rendering Path (CRP):

  1. Браузер получает HTML и парсит его, в итоге построит DOM. Так же происходит и с CSS файлом, он так же парсит его и образует CSSOM - объектная модель CSS. Он выглядит так же как DOM, но с соответствующими стилями для каждого узла.
  2. Когда сформировался DOM и CSSOM , происходит формирование дерева рендеринга (render tree) - это совокупность DOM и CSSOM.
    Это дерево, которое даёт представление о том, что в конечном итоге будет отображено на странице. Это означает, что оно захватывает только видимый контент(элементы и текст) и не включает, например, элементы, которые были скрыты с помощью CSS-правила display: none.
    Таким образом, render tree описывает визуальное представление DOM.
  3. Далее браузер выполняет отрисовку render tree.
    Для этого он:
    —рассчитывает положение и размеры каждого элемента в render tree, этот шаг называется Layout;
    Список свойств, изменение которых вызывает Layout:
    width и height;
    padding и margin;
    display;
    border;
    top, left, right и bottom;
    position;
    font-size и другие.
    —-выполняет рисование, этот шаг называется Paint.
    Список свойств, изменение которых вызывают Paint:
    color;
    background;
    visibility;
    border-style и другие.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
32
Q

Что такое Лексическое Окружение? (окружение)

A

В JavaScript у каждой выполняемой функции, блока кода и скрипта ЕСТЬ связанный с ними внутренний (скрытый) ОБЪЕКТ, называемый лексическим окружением LexicalEnvironment.

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

Получается, работа с переменными(например переприсваивание) - это работа со свойствами этого объекта лексического окружения.
Переменные инициализируются тогда, когда до них доходит ВЫПОЛНЕНИЕ, те они записываются в объект, появляются в этом окружении.

Global Environment(глобальное окружение){
car: ‘bmw’, - запись переменной
sayHi: Function - запись функции
}

По-другому дела обстоят с функциями (Function Declaration) - инициализация происходит тогда, когда СОЗДАЕТСЯ лексическое окружение.
По этому такие функции могут вызываться раньше, чем мы объявили функцию.

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

У внутреннего лексического окружения есть ссылка - outer на внешнее, те когда код хочет получить доступ к переменной – сначала происходит поиск во внутреннем лексическом окружении, затем во внешнем, затем в следующем и так далее, до глобального.
Есть глобальное лексическое окружение, где записываются глобальные переменные, функции и тд. Если у такого окружения нет более глобального окружения, то он будет означать null, вместо объекта.
Отсюда можем понять, что если например, у функции в своем окружении не нашлось нужной переменной, то она ищем во внешнем окружении, если там нет, то поднимается еще выше. Если в итоге не нашлось, то будет ошибка.

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

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

Пример1:
let name = “John”;

function sayHi() {
alert(“Hi, “ + name);
}

name = “Pete”; // (*) переприсвоилось значение

sayHi(); // Pete
//Функция получает текущее значение внешних переменных, то есть их ПОСЛЕДНЕЕ значение.

Пример2:

GlobalEnvironment{ counter: Function} - создалось глобальное окружение, куда записалась функция - FD. Такая запись { counter: Function} - это структура данных у окружения. Т.е. индетификатор - название переменной\функции, а значение - значение у примитива, а если функция, то Function.

const counter = ()=>{
// функция counter теперь может ссылаться на глобальное окружение в поисках необходимого:
counter =>GlobalEnvironment.
// При ВЫЗОВЕ функции counter создается ее лексическое окружение

let i=0
return () => { // возвращаем другую функцию
// так же ссылается на внешнее лекс. окружение - counter
//при вызове создается ее лексическое окружение
// тк в этой функции нет переменной i, то она ее найдет в функции counter и сохранится там измененное значение. При каждом вызове нашей возвращающейся функции, она будет выходить к окружению функции counter и брать оттуда переменную i.
console.log(++i)
}
}

const foo = counter() // здесь мы просто проинициализировали эту нашу функцию, которая вернулась из функции counter

foo() //1 // здесь мы вызываем нашу вернувшуюся функцию и в ней уже создается лекс. окружение.
foo() //2 // каждый раз при новом вызове этой функции создается новое лекс. окружение ее
foo() //3

Так же чтобы можно было отследить происходящие в лексическом окружении изменения, а также определить какое лексическое окружение является текущим, соответствующим данному этапу выполнения кода есть такое понятие как Контекст выполнения (execution context).
Первым контекстом выполнения, который создаётся при запуске JavaScript скрипта всегда является глобальный контекст выполнения (Global Execution Context). - глобальное окружение, глобальная область видимости.

Чтобы хранить и отслеживать контексты выполнения они формируются в стек контекстов выполнения (call stack) — список контекстов, организованных по принципу «последним пришёл — первым вышел».
Выполняемый контекст всегда является верхним элементом этого стека. После того, как необходимый код выполнится, связанный с ним контекст выполнения удалится, управление вернется в контекст, который находился элементом ниже, и теперь он будет верхним элементом — текущим контекстом выполнения.

Глобальная область видимости => Область видимости функции => Область видимости вложенной функции в предыдущую.
Зайдет последняя область и выйдет первой она же, когда выполнится и т.д.

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

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

A

Способность функции запомнить свое внешнее лексическое окружение.

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

Пример:
function getCounter() {
let counter = 0; // перезаписывается значение, тк окружение как было, так и осталось, в отличие от функции-замыкания - при новом вызове ее окружение формируется на новое.
return function() {
return counter++;
}
}
let count = getCounter(); // это замыкание, есть доступ к окружению внешней ее функции
console.log(count()); // 0
console.log(count()); // 1
console.log(count()); // 2
Мы храним анонимную внутреннюю функцию, возвращенную функцией getCounter в переменной count. Так как функция сount теперь замыкание, она может получать доступ к переменной counter в функции getCounter, даже после того, как та завершится.

Но обратите внимание, что значение counter не сбрасывается до 0 при каждом вызове count, как вроде бы она должна делать.

Так происходит, потому что при каждом вызове count(), создаётся новая область видимости, но есть только одна область видимости, созданная для getCounter, так как переменная counter объявлена в области видимости getCounter(), она увеличится при каждом вызове функции count, вместо того, чтобы сброситься до 0.

Примером замыкания можно назвать санку в thunk creator-е. Т.е. мы создаем thunk creator и вызываем его, в котором сидит сама санка. Санка же берет переданные данные из thunk creator-а. Таким образом получается замыкание.
Пример:

export const loginTC =
(data: any) => //это thunk creator
(dispatch: Dispatch<ActionsType>) => {
return data
}//сама санка, которая берет данные из thunk creator</ActionsType>

dispatch(loginTC(data))

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

Что такое рекурсия?

A

Рекурсия — это функция в своём теле вызывает саму себя.
Функцию, которая вызывает сама себя, называют рекурсивной функцией.
Вызов рекурсивной функции, называется рекурсивным вызовом.

Пример - Вычисление факториала с помощью рекурсии:

function f(n) {
if (n === 1){ // необходимо задать условия выхода из рекурсии, иначе она будет бесконечна
return 1;
}
return n * f(n - 1);
// 4f(4-1)
// 3
f(3-1) = 6
// 2*f(2-1) = 2
//когда в if удовлетворится условие, то вернет число 1
}
f(4);

Теперь можем выполнить подсчет: возвращается 1 как результат выполнения этой функции f(2-1), соответственно, 21=2, затем это значение возвращаем как результат этой функции f(3-1), значит 32=6, и последнее - 4*6=18

Общее количество вложенных вызовов называют глубиной рекурсии.

Пример2:

function pow(x, n) {
// лексическая область видимости:
//1 шаг - {x: 2, n: 3}
//2шаг - {x: 2, n: 2}
//3шаг - {x: 2, n: 1}
if (n == 1) {
return x; //3 шаг - возврат 1 как результат предыдущего вызова функции pow
} else {
return x * pow(x, n - 1);
}
}
pow(2, 3) ;
//21 = 2
// 2
2 = 4
// 2*4 = 8

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

Для чего нужна самовызывающаяся функция?

A

(function () {
…..
}) ( )

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

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

(function () {
var aName = “Barry”;
})();
// Variable name is not accessible from the outside scope
aName // throws “Uncaught ReferenceError: aName is not defined”

Главной идеей является то, что анонимная функция вызывается сразу после своего объявления. если нужно выполнить код один раз и сохранить его резульататы во “внешней среде” (без объявления глобальных переменных).
Мы не храним нигде ссылку на эту функцию. Нигде не храним возвращаемое значение. Так только функция инициализирована, она тут же вызывается.
Это может быть удобным вариантом инициализации, например, мы инициализируем и прикрепляем функции обработчиков событий один раз, после объявления функции вызываем ее, и теряем с ней связь.

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

Чем отличается интерпретатор и компилятор?

A

Простой интерпретатор анализирует и тут же выполняет программу построчно (покомандно), по мере поступления её исходного кода.
Недостаток - интерпретатору приходится проделывать одну и ту же работу, когда используете одинаковый код несколько раз.
Например, если вы находитесь в цикле, интерпретатор будет анализировать одни и те же строки снова и снова.
Также, такой интерпретатор обнаруживает ошибки в коде только при попытке выполнения строки с ошибкой. И никак не сможет сообщить об ошибке в коде с самого начала.

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

Также, компилятор сразу может сообщить, что в коде присутствует ошибка.

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

var a = 2;

Эта программа, вполне вероятно, будет разбита на следующие лексемы:
var — объявление переменной,
a — идентификатор (имя) переменной,
= — оператор присваивания,
2 — число,
; — конец инструкции

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

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

A

Чтобы можно было отследить происходящие в лексическом окружении изменения, а также определить какое лексическое окружение является текущим, соответствующим данному этапу выполнения кода есть такое понятие как Контекст выполнения (execution context).
Первым контекстом выполнения, который создаётся при запуске JavaScript скрипта всегда является глобальный контекст выполнения (Global Execution Context). - глобальное окружение, глобальная область видимости.

Чтобы хранить и отслеживать контексты выполнения они формируются в стек контекстов выполнения (call stack) — список контекстов, организованных по принципу «последним пришёл — первым вышел».
Выполняемый контекст всегда является верхним элементом этого стека. После того, как необходимый код выполнится, связанный с ним контекст выполнения удалится, управление вернется в контекст, который находился элементом ниже, и теперь он будет верхним элементом — текущим контекстом выполнения.

Глобальная область видимости => Область видимости функции => Область видимости вложенной функции в предыдущую.
Зайдет последняя область и выйдет первой она же, когда выполнится и т.д.

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

Что такое каррирование?

A

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

Пример:

обычная функция:
function volume(l,w,h) {
return l * w * h;
}
const aCylinder = volume(100,20,90) // 180000l

каррирование:
function volume(l) {
return (w) => {
return (h) => {
return l * w * h
}
}
}
const aCylinder = volume(100)(20)(90) // 180000
Суть в том, что самая последняя вложенная возвращаемая функция имеет доступ к окружению предыдущих функций

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

Отличие proto от prototype?

A

Это свойства объекта.

У всех объектов(объект, массив, number, string, boolean(помним, что если поставить точку, то создается обертка, которая на время создает объект), функция, функ. выражение, стрелочная функция, класс(это навороченная функция, а значит объект)) есть proto.

proto - это объект. proto, относящиеся к одному типу объектов, равны, т.к. они относятся к одному и тому же объекту proto, если разные типы, то не равны:

  1. {}.proto === {}.proto // true, т.к. один тип
  2. proto всех видов функций(даже класс), будут так же равны
  3. function add.proto === const a = ()=>{}.proto // true, т.к. один тип
  4. {}.proto === function add.proto
    // false , т.к. разные типы

Prototype - независимый объект, у которого есть свои свойства и методы(т.е. это те, от кого все пошло)(сlass String{}, class Samurai{}, function First(){}(функции-конструкторы)).
Он есть только у КЛАССА и ФУНКЦИИ-КОНСТРУТОРА.

proto ссылается на прототип(prototype) того класса, с помощью которого был создан экземпляр:
1. сonst a = new String(‘aaa’)//экземпляр класса
a.proto === String.prototype // true
//__proto__ указывает на прототип String.prototype по этому true

  1. сlass YouTube{} === Function.prototype // true, т.к. создан с помощью new Function()
  2. class Samurai{ }//класс
    const s = new Samurai()//экземпляр класса
    s.proto === Samurai.prototype // true
  3. Array.proto === Function.prototype
    // true, тк все классы - это функции
    //здесь берется подкапотный new Array()
  4. class User{ }
    User.proto === Function.prototype
    User.proto.proto === Object.prototype
    User.proto.proto .proto===null
    //User создается с помощью new Function
    //второе .proto будет относится уже к Function.prototype, а создался он с помощью new Object
    //третье .proto относится уже к Object.prototype, а его proto уже никуда не ссылается, т.к. это объект

Зачем эти прото и прототип?

let dim = {name: Dim}

dim.toString()// у объекта нет такого методы, и под капотом происходит это:
dim.proto => Object.prototype =>{toString(){ }}
// смотрит на что ссылается прото, лезет в него(Object) и если в этом объекте сидит этот метод, то берет его.

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

Какие области видимости бывают?

A

Но не все переменные в нашем коде одинаково доступны. Доступна ли переменная и как получить к ней доступ, определяют области видимости.

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

1.Глобальная область видимости — это самая внешняя коробка из всех. Когда мы «просто объявляем переменную», вне функций, вне модулей, то эта переменная попадает в глобальную область видимости.

2.Блочная область видимости ограничена программным блоком, обозначенным при помощи { и }. Например, if или switch

3.Функциональная область видимости — это область видимости в пределах тела функции.

  1. Модульная область видимости - импорт\экспорт переменных между файлами. Модуль - это файлы. Переменные, объявленные в этом модуле будут доступны только там, если же их импортируют в другой модуль, то они будут доступны в этом модуле.

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

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

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

Есть ли this в стрелочных функциях?

A

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

class Dog {
constructor(name){
this.name = name; // здесь будет сидеть ‘Bim’
}
eat(food){
console.log(‘method’, this)
// выведет в консоль Dog {name: Bim}
food.forEach((item) => {
console.log(‘arrow func’, this)
// выведет в консоль Dog {name: Bim}, это доказывается, что у стрелочной функции нет своей this и она его берет из внешнего контекста
console.log(${this.name} is eating ${item})
});
}
}

const bim = new Dog(‘Bim’); // создаем новый объект Dog

bim.eat([‘bone’, ‘cookie’])

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

Что такое Виртуальный Дом?

A

Виртуальный объект DOM — облегченная копия Реального Дома.
Виртуальный объект DOM имеет те же свойства, что и реальный объект DOM, но у него нет реальной возможности напрямую изменять то, что отображается на экране. По этому и называется легковесной копией.

Т.е. у него есть свойства, как у Реального Дома - свойства часто ссылаются как на то, С ЧЕМ необходимо что-либо сделать (например, название узла). document.innerHTML - отобразит текст, который содержится в элементе html.

Но нет методов, т.е. он не может что-то сделать с элементом:
На методы часто ссылаются как на ТО, что необходимо сделать (например, удалить узел):
document.getElementById(id) - получить элемент с указанным id из всего html

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

Зачем нужен PATCH, если есть PUT?

A

PUT подразумевает под собой, что мы отправим полностью объект, который сидит на серваке, но где-то с необходимыми обновленными свойствами
PATCH - отправит только те свойства, которые хотим изменить.
Плюс PATCH в том, чтобы не происходило конфликтов. Например, один человек изменил свойство в объекте и отправил через PUT , через секунду другой человек отправляет объект с измененным другим свойством, но в этом объекте по-прежнему сидит то старое свойство, которое изменил первый человек. В результате это старое свойство снова появляется на сервере. С PATCH мы точечно меняем свойства.

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

Как образуется обычный DOM из HTML-страницы?

A

DOM имеет древовидную структуру, состоящую из ДОМ-узлов.
Браузер получает HTML-файл, парсит его и вызывая document.createElement для каждого узла в DOM. Дом будет состоять из Дом-элементов - это объекты-узлы . Далее можно будет работать с ним, применяя, например, const el = document.getElementById(‘div’) и уже что-то с этим элементом делая, например,
el.innerHTML=’HELLO!!!’, сразу же эти изменения фиксируются в DOM и HTML-страница перерисовывается.

Виртуальный Дом уже относится к Реакту, не касаясь обычного HTML-я.

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

document.querySelector, зачем он нужен?

A

Это метод для объекта document, позволяющий найти HTML-элемент с помощью CSS-селекторов:
document.querySelector(‘.name’)
// найдет первый попавшийся HTML-элемент, который содержит этот класс
С полученным элементом можно будет производить различные манипуляции: менять его текст, атрибуты, CSS стили
Если совпадений не найдено, то возвращается значение null.
Не допускается использование CSS псевдоэлементов, вернет так же null.
Если необходимо найти несколько, то .querySelectorAll вернет массив из этих элементов.

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

Что такое промис? Какие состояния бывают у промиса? Какие статические методы бывают у промиса? Какие методы бывают у промиса?

A

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

Промис может находиться в одном из трёх состояний:
pending — стартовое состояние, операция стартовала;
fulfilled — получен результат;
rejected — ошибка.

У промиса есть 3 метода then(), catch() и finally(), которые позволяют использовать результат вычисления функции, которые содержатся в промисе.

С помощью then() мы подписываемся на момент, когда промис зарезолвится(resolve).
Таким образом, функция-коллбэк, которую передали в .then, вызывается, и в этот колбэк передаются данные, которыми зарезолвился промис. then() всегда возвращает НОВЫЙ промис.
const promis = axios.get(‘……….’)
promis.then((data)=>{выполнится, когда промис зарезолвился})

Пишем более кратко:
axios.get(‘……….’).then((data)=>{выполнится, когда промис зарезолвился})

С помощью catch обрабатываем ошибку, если она произошла:
axios.get(‘……….’)
.then((data)=>{выполнится, когда промис зарезолвился})
.catch(error=>{выполнится, когда промис зареджектится})

finally() выполнится в любом случае, независимо от того была ли ошибка или нет:
axios.get(‘……….’)
.then((data)=>{выполнится, когда промис зарезолвился})
.catch(error=>{выполнится, когда промис зареджектится})
.finally(()=>{выполнится не зависимо от того, что произойдет})

Все те промисы, которые приходят, они созданы с помощью класса Promise через
new Promise(()=>{….}) -создается экземпляр класса

У самого класса Promise есть так называемые статические методы, которые относятся только к нему, а then(), catch() и finally() - относятся к экземплярам. Вот эти статические методы:

  1. Promise.all:
    если нам нужно запустить множество промисов параллельно и дождаться, пока все они выполнятся.
    Принимает массив промисов и возвращает новый промис тогда, когда эти все промисы зарезолвятся.
    Результатом промиса будет массив из результатов каждого промиса.
    Promise.all([
    new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
    new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
    new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
    ]).then(alert); // когда все промисы выполнятся, результат будет 1,2,3, но .then() так же вернет новый промис с этим результатом.
    // каждый промис даёт элемент массива.
    Результат будет в такой же последовательности, как и промисы вне зависимости от того, кто быстрее зарезолвился.
    Если хоть в каком-то промисе произошла ошибка, то итоговый промис никогда уже не зарезолвится. Будет ошибка.
  2. Есть метод Promise.allSettled, который помогает обработать промис даже если в каких-то промисах произошла ошибка. Результат будет таким:

[ // приходит уже не просто массив, а массив объектов, где лежат инфо о каждом промисе. Если он зарезолвился, то в value сидит ответ, если нет - то ошибка сидит.
{status: ‘fulfilled’, value: …объект ответа…},
{status: ‘fulfilled’, value: …объект ответа…},
{status: ‘rejected’, reason: …объект ошибки…}
] // по этому обрабатывать нужно как объект, а не массив: Promise.allSettled(…).then(result=>result.value)

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

  1. Метод Promise.resolved([1,2,3])
    Вернет сразу зарезолвенный промис, например, может понадобиться, когда нужна заглушка, и хотим симитировать получение данных с сервера, но бэк еще не готов. Просто создаем такой промис и вставляем нужные нам данные. И далее уже можем обрабатывать с помощью .then() этот промис.
  2. Метод Promise.reject({message: ‘Some error’})
    Cоздаем промис ошибкой. Возвращает зарежектнутый промис, который можем обрабатывать .catch()
  3. Метод Promise.race([…, …., ….]):
    Принимает массив промисов, ждёт только ПЕРВЫЙ выполненный промис, из которого берёт результат или ошибку. После этого остальные промисы игнорируются.
  4. Метод Promise.any([…, …., ….]):
    Принимает массив промисов, ждёт только ПЕРВЫЙ УСПЕШНО выполненный промис, из которого берёт результат.
    Если первый был с ошибкой, то берется следующий, если он успешен и т.д.
    Если отклонились все промисы, то возвращённый объект Promise будет отклонён с помощью AggregateError – специального объекта ошибок, который хранит все ошибки промисов в своём свойстве errors.
    ———————————————————————–
    Есть простой синтаксический сахар - asinc/await, который используется ВМЕСТО .then().
    сonst promis = await axios.get(‘получим с сервера юзера под id2’)//await возвращает результат зарезолвенного промиса
    console.log(promis ) // {name:’Vasya’}
    // в переменной promis будет результат зарезолвенного промиса с помощью await БЕЗ использования метода .then().То есть результат res внутри .then((res)=>console.log(res)) === результату в переменной, где применяется await. ( then((res)=>///) - res- здесь будет результат зарезолвенного промиса )

Если переменные с await-ом стоят друг за другом, то остальные после первого будут дожидаться пока первый выполнится и т.д.:
const foo = async ()=>{
const pr1= await fetch(‘……..’) // выполняется…
const pr2= await fetch(‘……..’)// ждет пока 1й вып.
const pr3= await fetch(‘……..’)// ждет пока 2й вып.
}
Эти переменные можно использовать, например засетать :
const [user, setUser] = useState()
setUser(pr1.user)

Если один из запросов с ошибкой, то следующие прерываются и ловятся ошибкой.

В async функции можно использовать try\catch\finally:
const foo = async ()=>{
try{
const pr1= await fetch(‘……..’) // выполняется…
const pr2= await fetch(‘……..’)// ждет пока 1й вып.
const pr3= await fetch(‘……..’)// ждет пока 2й вып.
} catch(err){
console.log(‘‘ERROR’’, err)
}
}

await обязательно должен быть в связке с async, по этому не забываем ставить async перед функцией.

Если после await следует ниже код, то он не будет выполнятся, если не выполнится await
const pr1= await fetch(‘……..’)
сonsole.log(‘Hello!’)
Это тоже самое, если бы мы писали с .then():
fetch(‘……..’).then(сonsole.log(‘Hello!’))
//если fetch не зарезолвится, то и .then не выполнится

Если же мы берем данные, которые фиксированные, а не промис и пропускаем через await, то они так же поместятся в переменную, как поместился бы и промис зарезолвенный:
const api={
save(){},
read(){
return {name: ‘Alex’}
//здесь обычный объект, не промис
}

async function give(){
await api.save()
let data = await api.read()
// эвэйтим просто данные, не промис, но в итоге в //переменную все равно записываются данные - //{name: ‘Alex’}
console.log(data)
}
give()
Эвэйтить можно заранее, например, если в будущем планируется модификация объекта, где вместо этих данных будет промис, таким образом, можем заранее предугадать, чтобы потом не переписывать код.

Как сделать промисификацию:
const api={
save(){},
async read(){ //сделать функцию ассинхронной, любая ассинх.функция возвращает промис.
return {name: ‘Alex’}
//либо вместо async написать new Promis(resolve=>resolve({name: ‘Alex’}))
//либо Promis.resolve({name: ‘Alex’})
}

async function give(){
await api.save()
let data = await api.read()
// эвэйтим просто данные, не промис, но в итоге в //переменную все равно записываются данные - //{name: ‘Alex’}
console.log(data)
}
give()

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

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

A

Так как метод .then() возвращает всегда новый промис, мы можем делать цепочку вызовов:
findUsers(3)//отрезолвился промис
.then(user=>user.name)//возвращает новый промис с именем пользователя//user - это response-объект.
.then(name=> console.log(name)) // это имя пользователя выводится в консоль.

Если будет так:
findUsers(3).then(user=>user.name)
findUsers(3).then(name=> console.log(name))
то это уже не цепочка промисов, когда мы каждый раз даже к одному промису применяем метод по-отдельности.

Как отрабатывает .catch() в цепочке промисов:
pr(1)
.then(user=> return user.friend)
.then(user.friend=> return pr(user.friend))
.catch(err=>{
console.log(‘Try later’)
return pr(friendId)
})
.then(pr(friendId)=> console.log(‘hello’) return)
//если перед catch произошла ошибка в каком-либо из then, то catch отработает ее и после него then-ы продолжать работать. Но т.к. здесь цепочка промисов и зарезолвенные промисы передаются из одно в другой, то может произойти разрыв цепочки из-за ошибки. Чтоб такого не было, мы можем вернуть из catch что-то. То есть вернется промис.

49
Q

Как создается промис?

A

Через конструкцию new Promis((resolved, reject)=>{ тело промиса}) , куда передается функция-коллбэк с двумя параметрами. Так же можем обрабатывать промис с помощью методов .then() .catch().

function getPromis(){
сonst promis = new Promis((resolved, reject)=>{
return resolve(Math.random())
//возвращаем в этом случае зарезолвенный промис
})
}
getPromis().then(pr=>console.log(pr))
//обработаем зарезолвенный промис

50
Q

Что такое defer async?

A

Это атрибуты скрипта в HTML.

Обычно браузеры загружают

 синхронно, во время разбора документа. Поэтому принято добавлять скрипты в конец документа, перед </body>, чтобы они не тормозили загрузку страницы.

async:
При обнаружении

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

defer :
Указывает браузеру что скрипт должен выполняться после разбора документа, но ДО события DOMContentLoaded(событие DOMContentLoaded происходит, когда браузер разобрал HTML-страницу и составил DOM-дерево).
Скрипты с атрибутом defer будут предотвращать запуск события DOMContentLoaded до тех пор, пока скрипт не загрузится полностью и не завершится его инициализация.
Если стоят два скрипта, то первым всегда выполнится script1.js, который подключён раньше. Даже если script2.js загрузится раньше, он будет выполнен после первого скрипта:




51
Q

Что такое Rest API? Как происходит взаимодействие клиента с сервером и как отвечает сервер на запрос клиента?

A

API (Application Programming Interface) — язык, на котором приложения общаются между собой. С помощью API одно приложение может использовать возможности другого приложения.
Например, интернет-магазин отправляет запрос банковскому приложению, передавая ему реквизиты свои и покупателя, а также сумму для оплаты. А банковское приложение возвращает ответ, в котором сообщается, прошла ли оплата успешно.

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

Как происходит взаимодействие клиента с сервером?

  1. Запрос REST API от клиента к серверу всегда состоит из следующих элементов, которые нам необходимо знать:
    –конечная точка (endpoint) — адрес, по которому отправляется запрос.
    Например, она может выглядеть так:
    best-delivery.com/orders/list, чтобы посмотреть список заказов.
    best-delivery.com - базовый адрес
    /orders/list - конечная точка(endpoint)
    –параметры — делятся на параметры пути и параметры запроса.
    Например, best-delivery.com/orders/{userId}/list {userId} — это параметр пути. Вместо {userId} нужно подставить идентификатор конкретного пользователя, тогда запрос вернет список заказов этого пользователя.
    Или best-delivery.com/orders/list?orderId=123456 orderId — это параметр запроса. Такой запрос вернет информацию о конкретном заказе.
    –заголовки (headers) - там находится вся информация, необходимая для корректной обработки запроса, например, определяется формат передаваемых данных.
    –тело запроса (body) — данные для обработки, как правило в формате JSON.
    Например, запрос для службы доставки может содержать номер заказа, адрес, телефон для связи и интервал доставки, примерно так:
    {“orderId”:123456, “address”:”119021, Москва, ул. Льва Толстого, 16”, “phone”:”+74957397000”, “time_interval”:”9:00-11:00”}.

Как отвечает сервер на запрос клиенту?

После выполнения REST API запроса сервер вернет клиентскому приложению ответ. Он включает код ответа, заголовки и тело ответа.

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

–тело ответа — это информация, которую запрашивал клиент. Ответ тоже чаще всего передается в формате JSON. Но тело ответа может быть и пустым.

–код ответа — это признак успешности выполнения запроса.
200 – ОК - Если клиентом были запрошены какие-либо данные, то они находятся в заголовке или теле сообщения.
404 – Not found. Ресурс не найден.
403 – Forbidden. Доступ к сервису запрещен.

1XX - информационные,
2XX - успешные,
3XX - перенаправления (редирект),
4XX - ошибки клиента
5XX - ошибки сервера

GET - получение данных с сервера (обычно в формате JSON, или XML).
Операция получения данных не может приводить к изменению состояния сервера.
POST - добавление новых данных на сервер.
PUT - модификация существующих данных на сервере
DELETE - удаление данных на сервере
OPTIONS - preflight запрос. Проверяет можем ли мы с одного адреса делать запрос на другой

52
Q

Что такое xss-атака?

A

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

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

Или злоумышленник может незаметно для жертвы перенаправить его на другую страницу-клон. Эта страница может выглядеть идентичной. Пользователь введет свои личные данные и они окажутся доступны злоумышленнику.

53
Q

Принципы ООП?

A

Инкапсуляция
Полиморфизм
Наследование

54
Q

this в FD и FE

A

Для функций, объявленных через function f( ) { }, this вычисляется в момент вызова и равен объекту перед точкой. Если такого объекта нет — тогда this будет указывать на глобальный контекст (window)

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

const user = {
name: ‘Bob’,
userThis: this,
func() {
console.log(this);
},
arrowFunc: () => {
console.log(this);
}
};

console.log(user.userThis); // this указывает на window.
user.func(); // объектом перед точкой является user, поэтому this ссылается на объект user.
user.arrowFunc(); // стрелочная функция запомнила свой контекст в момент создания, то и при вызове она будет ссылаться именно на него. Таким образом мы получаем window.
Еще объяснение:
В случае вызова user.arrowFunc(), стрелочная функция arrowFunc создана в контексте объекта user, но она не имеет своего собственного this. Она сохраняет лексическое окружение, в котором была создана, и в данном случае, это окружение - это глобальный объект (window в браузере). Поэтому при вызове user.arrowFunc(), в консоль будет выведен глобальный объект (window).

55
Q

this в методах call() apply() bind()

A

call() - нет необходимости создавать вспомогательную функцию для того, чтобы передать в качестве this нужный объект.
const car1 = {
color: ‘red’,
show(a, b) {
console.log(this.color);
console.log(a, b);
}

const car2 = {
color: ‘black’,
}
car1.show.call(car2, 1, 2) // black, 1, 2
// вызываем сразу же метод show с помощью метода call() и передаем в аргумент другой объект car2, который будет теперь контекстом для this вместо контекста car1
// если нужно передать аргументы, то перечисляем их через запятую.
Методом apply() идентичен, за исключением - что мы передаем аргументы массиве - car1.show.call(car2, [1, 2])
//передача аргументов - не обязательна и в том и другом методе. В таком случае они полностью идентичны.

Метод bind() создает функцию-обертку:
const b = car1.show.bind(car2, 2, 3)
которую нужно будет вызвать:
b()
// так же аргументы по желанию
———————————————————————
В данном случае мы не можем привязать к this контекст через call() !!!

сonst user2={
name: ‘Vasya’
}

const user = {
name: ‘Bob’,
arrowFunc: () => {
console.log(this);
}.call(user2)
};

user.arrowFunc() // будет Bob
user.arrowFunc.call(user2) // и если уберем около стрелочной функции .call(user2), то таким образом можно привязать, будет Vasya

Мы не можем перепривязывать контект!!!
user.arrowFunc.bind(user2).call(user3)
Здесь контекст будет user2

56
Q

Что такое классы и для чего они нужны?

A
  1. Классы нужны для создания однотипных объектов
    –с помощью функции-конструктора - (например, есть функция-конструктор животное, которое имеет базовые свойства и методы(ходить, пить, есть). Теперь от такого конструктора мы можем создавать экземпляры.
    Рассмотрим на примере action:
    function DeleteUserAction(userId){//назв.с бол.б.
    this.type = “DELETE_USER”
    this.payload:{
    userId: userId
    } //создали функцию-конструктор
    }

сonst action1 = new DeleteUserAction(35432)
сonst action2 = new DeleteUserAction(53322)
//создали экземпляры

–с помощью класса:
class DeleteUserAction{
constructor(){
this.type = “DELETE_USER”
this.payload:{
userId: userId
}
}
}
сonst action1 = new DeleteUserAction(35432)
сonst action2 = new DeleteUserAction(53322)
//так же вызываем и получаем экзмемпляр

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

function User(name, site){
this.name = name
this.site = site
}//объект со свойствами

User.ptototype.hello = function(){….}
//присоединили к объекту метод через прото

сonst u1 = new User(‘fg’, ‘ggg’)
сonst u2 = new User(fg’, ‘ggg’)

u1.hello()//теперь можем вызывать метод, его this будет ссылаться на юзера1. Помним, что у FD this формируется на момент вызова.
u2.hello()

Теперь в классах делается все проще:
вместо того, чтобы цеплять к прототипу, теперь метода пишется просто в классе.
Так же на один и тот же метод будут ссылаться:
u1.hello() === u2.hello() //true

  1. С помощью класса мы можем реализовывать ООП парадигму - наследование, инкапсуляция, полиморфизм.

—Инкапсуляция - сокрытие деталей, например, можем скрыть доступ к свойствами, например, _name, но это условная договоренность между разработчиками, мы все равно сможем получить доступ к этому свойству user._name.
Можно использовать #user, в таком случае мы уже не сможем получить доступ user.#name.

Наилучший вариант - геттеры и сетторы:

get name(){return this.#name}
//в таком случае сможем прочитать свойство
set name(value){this.#name = value}
//можем изменять свойство пришедшим знач-м.

user.name //так обращаемся у геттеру, чтобы получить свойство
user.name = ‘Igor’ // так обращаемся к сеттеру, чтобы установить значение для свойства

—Наследование:

//класс Кодер унаследует все свойства и методы от класса Юзер
сlass Coder extends User{
сonstructor(name, idUser, tech){
//передаем все свойства и Юзера и Кодера
super(name, idUser) //для унаслед-х св-в
this.tech = tech //для свойств Кодера
}
code(){console.log(this.tech)}
}

const coder1 = new Coder(‘Igor’, ‘4773663’, ‘JS’)
//передаем значения для свойств, которые унаследовались от класса Юзер
сoder1.hello()
сoder1.code() // JS
// так же может вызывать унаследованный метод

Так ж можем и переопределить метод унаследованный или дополнить его своим кодом:
hello(){
super.hello()//вызываем унаследованный метод
concole.log(‘HI!’)//дополнили свои кодом
}

—Полиморфизм:
например, мы собираем в массив объекты одной сущности(образовались от коренного какого-то класса неважно как, либо это экземпляр, либо с помощью расширения класса)
const arr = [u1, u2, coder1] и у них всех есть то, что есть в коренном классе, например, метод hello()
arr.forEach((u)=> u.hello())//вызываем у каждого элемента этот метод, зная, что они все имеют этот метод от коренного класса.

Объяснение:
полиморфизм даёт возможность использовать одни и те же методы для объектов разных классов. Неважно, как эти объекты устроены, — в ООП можно сказать самолёту и квадрокоптеру: «Лети», и они будут делать это как умеют: квадрокоптер закрутит лопастями, а самолёт начнёт разгон по взлётно-посадочной полосе.

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

Как пример можно рассмотреть классовые компоненты в Реакте:

class ProfilePage extends React.Component{
//класс ПрофайлПейдж унаследуется от класса Реакта

constructor(props){
super(props)
//передаем к родит. компоненте React.Component пропсы, чтобы она их себе записала.
}

render(){ return ‘…..’}

}

<ProfilePage></ProfilePage>

//если классовую компоненту отрисовываем как тег, то
сonct compl = new ProfilePage({title: ‘Hi’})
// то Реакт создает экземпляр объекта на основе этого класса и если есть пропсы, то упаковывает их в объект
compl.render() // и вызывает рендер

сompl.render()//отрендери мне
compl.componentDidMounting()

57
Q

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

A

Когда мы захотим прочитать свойство из экземпляра, а оно отсутствует, то JavaScript автоматически берёт его из прототипа.
Это называется «прототипным наследованием».

—Можно задать прототип вручную:
var animal = { eats: true };
var rabbit = { jumps: true };

rabbit.__proto__ = animal; // унаследовать

alert(rabbit.eats); // true
alert(rabbit.jumps); // true

—Также можно создать объект с явным прототипов с помощью Object.create:

var animal = { eats: true };

var rabbit = Object.create(animal);

alert(rabbit.eats); // true

Специальные значения null и undefined стоят особняком. У них нет объектов-обёрток, так что методы и свойства им недоступны. Также у них нет соответствующих прототипов.

Цепочка прототипов, пример:
Null <= [[Prototype]] <=
<=Object.prototype, который имеет свои методы:
toString: function other object methods <= [[Prototype]] <=
<= Array.prototype, который имеет свои методы: slice: function other array methods <= [[Prototype]] <=
[1, 2, 3]

https://learn.javascript.ru/native-prototypes (схема есть полная и объяснение)

Самое сложное происходит со строками, числами и булевыми значениями.
Они не объекты.
Но если мы попытаемся получить доступ к их свойствам, то тогда будет создан временный объект-обёртка с использованием встроенных конструкторов String, Number и Boolean, который предоставит методы и после этого исчезнет.

Эти объекты создаются невидимо для нас, и большая часть движков оптимизирует этот процесс, но спецификация описывает это именно таким образом.
Методы этих объектов также находятся в прототипах, доступных как String.prototype, Number.prototype и Boolean.prototype.

58
Q

Чем отличаются let const var?

A

Переменной, объявленной через let, можно не присваивать начальное значение. Значение этой переменной можно переопределять.
Переменной, объявленной через const, необходимо присвоить начальное значение. Его переопределять нельзя.
Они имеют блочную область видимости - значит недоступны за пределами каких-то блоков(условия, функции и тд)
Нельзя к ним обращаться до их объявления.
Переменной, объявленной через var, можно обращаться ДО объявления(hosting) ее, но выведет undefined, можно не присваивать начальное значение. У нее функциональная область видимости - значит она доступна в функции, но недоступна за ее пределами.

59
Q

Что такое контекст? и this?

A

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

this имеет различные значения в зависимости от того, где используется:
—–Сама по себе - this относится к глобальному объекту (window).
—–В методе(FD) - this относится к родительскому объекту.(в момент вызова)
—–В функции - this относится к глобальному объекту.
—–В функции в ‘strict mode’(‘use strict’) - this = undefined.
Подробнее:
В строгом режиме, значение this внутри метода объекта не будет автоматически связано с объектом(в момент вызова), а будет равно undefined.
В строгом режиме это было сделано для уменьшения ошибок и предотвращения неявного связывания this с глобальным объектом (как это было в нестрогом режиме). Это требование строгого режима обеспечивает более предсказуемое поведение и помогает избежать некоторых ошибок, связанных с неправильным использованием this.
!!! Вместо использования глобального объекта, в строгом режиме значение this остается undefined, что приводит к ошибке, и программист должен явно указать контекст с использованием методов !!! call() или apply().
—–В стрелочной функции - this относится к глобальному объекты (window). (там где они были созданы, в момент создания)
—- Если стрелочная находится внутри объекта, а не в глобальной области, то this будет равно undefined в этом случае - this.prop, а так this == window (там где они были созданы, в момент создания):
var obj = {
prop: “value”,
method: () => {
console.log(this === window); // true (в браузере)
console.log(this.prop); // undefined, так как глобальный объект не имеет свойства prop
}
};
obj.method();
!!!!!То есть получается, что при создании функции method ее this равен глобальному объекту, а у этого объекта нет свойства prop, по этому получается undefined.!!!!!
Решением может быть привязать контекст, чтобы this ссылалась на объект с помощью bind(this) call(this) apply(this):
var obj = {
prop: “value”,
method: function() {
var arrowFunction = () => {
console.log(this.prop);
};
// Используем bind для привязки контекста
var boundArrowFunction = arrowFunction.bind(this);
boundArrowFunction();
}
};
obj.method(); // Вывод: “value”
——В событии - this ссылается на элемент запустивший событие.

this - ссылка на контекст(объект)
контекст - объект, на который ссылается this, и зависит от того, где используется this(описано выше)

60
Q

Назовите паттерн Publisher(Observable)/Subscriber (Издатель/Подписчик). Назовите примеры подписки (subscribe) в Реакте или в нативном js?

A
  1. Подписываемся на стор:
    store.subscribe(function subscriber(){})
    //функция внутренняя выполнится тогда, когда обновится стор, т.е. подписчик подписывается и ожидает изменений, после чего запустит функцию.
  2. Вешаем обработчик событий на элемент:
    button.addEventListener(‘click’, function subscriber(){})
    //функция запустится когда произойдет событие
    И также если отписываемся от события:
    (только нужно создать переменную, когда вешаем обработчик, иначе подписка и отписка будут ссылаться на разные функции)
    button.addEventListener(‘click’, function subscriber(){})//неправильно
    button.removeEventListener(‘click’, function subscriber(){})//неправильно
    const sub = button.addEventListener(‘click’, function subscriber(){})//правильно!
    sub.removeEventListener(‘click’, function subscriber(){})//правильно!
  3. Подписываемся с помощью then на зарезолвенный промис:
    promises.then((res)=> …)
    //ожидает когда промис зарезолвится и тогда выполнится внутреняя функция
  4. По истечению времени выполнится функция из сетТаймаута:
    setTimeout(function subscriber(){}, 1000)
  5. useSelector тоже является подписчиком. Он подписывается на изменения стейта.
  6. Когда вешаем onClick на наш кастомный тег(компоненту):

<AppGetState onClick={()=>{}} />
//сработает коллбэк, когда произойдет событие

61
Q

Что такое полифилы?

A

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

Для перевода нового синтаксиса в старый используется:
Babel – это транспилер. Он переписывает современный JavaScript-код в предыдущий стандарт.

Современные сборщики проектов, такие как webpack или brunch, предоставляют возможность запускать транспилер автоматически после каждого изменения кода, что позволяет экономить время.

62
Q

Поверхностное и глубокое копирование? Что хорошо, ч то плохо использовать?

A

С точки зрения глубокого и поверхностного копирования можно создавать два вида переменных. Первый — это примитив. Его основные типы: строка, число, булево значение, неопределенное значение и null. Второй вид — переменная-ссылка, известная как объект.

При копировании примитивного значения ему присваивается новый адрес в памяти:
const variable1 = “Hello” // указывает на адрес памяти: 0x001
const variable2 = 100 // указывает на адрес памяти: 0x002
А когда копируется ссылочная переменная, новая переменная будет указывать на место скопированной в памяти.
Т.е. объекты - ссылочный тип данных.

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

Методы глубокого копирования:
1. Если объект, который нужно скопировать, находится на глубине только одного уровня, для создания глубокой копии рекомендуется использовать оператор spread.

  1. Для более сложных объектов стоит применять комбинацию JSON.parse() и JSON.stringify():
    const fruitStand = {
    apples: 3
    }
    const fruitStandCopy = JSON.parse(JSON.stringify(fruitStand))
    //сначала объект превратили в строку, затем распарсили обратно в уже новый объект

fruitStandCopy.apples = 7
console.log(fruitStand.apples) // 3
console.log(fruitStandCopy.apples) // 7
Внимание!!! Однако эта техника рискованна, поскольку функции внутри исходного объекта не будут скопированы.

  1. Для создания глубоких копий также можно использовать сторонние библиотеки, такие как lodash. Оттуда взять метод .cloneDeep(value)
  2. Использовать глобальный метод structuredClone(), который позволяет сделать полную копию объекта. К сожалению он поддерживается только современными браузерами. Он копирует любую вложенность.

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

63
Q

Что такое bubbling?(всплытие)
Что такое Capturing?(противоположно всплытию, погружение)

A

Это всплытие вверх по иерархии. Если произошел клик по ребенку-элементу, то всплытие пойдет вверх к родителю, затем к прародителю. Будут запущены все их обработчики. Если произошел клик по родителю, то ребенок уже не будет затронут.

Для обратного действия используется addEventListener() с его третьим необязательным параметром useCapture(1й- имя события, 2й - функция, которая обрабатывает). Этот параметр всегда находится в состоянии false. Если поставим его в true, то при нажатии на дочерний элемент, поток событий будет начинаться с прародителя.

document.querySelector(“#parent”).addEventListener(“click”, () => {
document.querySelector(“#parent > p”).textContent = “Parent Clicked!”;
console.log(“Parent Clicked”);
}, true); // Параметр useCapture теперь имеет значение true

64
Q

Методы some(), every(), flat(), includes(), indexOf(), Array.from() (методы МАССИВОВ и строк)

A

some() позволяет узнать, есть ли в массиве хотя бы один элемент, удовлетворяющий условию. Результат вызова будет true, если хоть один элемент имеет совпадение. Если ни одного - вернет false.

every() - удовлетворяют ли все элементы в массиве условию. Если все - true, если хотя бы один не удовлетворяет - false.

flat() - возвращает новый массив и уменьшает вложенность массива на заданное количество уровней. По умолчанию стоит 1 - задает число, на которое нужно уменьшить вложенность.
(есть задача перепеси этого методы вручную )

includes() - у массивов и строк есть. Для массивов: проверяет, есть ли искомый элемент в массиве. Для строк: проверяет, есть ли искомая подстрока в строке. Если есть - тру, нет- фолс.

indexOf() - у массивов и строк есть. Передаем то, что нужно оттыскать в массиве или в строке(‘чебур’), вернет индекс первого попавшегося совпадения, если не нашел, то -1

Array.from() создаёт новый массив на основе переданного объекта.
Объект должен быть либо массивоподобным (как строка или объект arguments), либо итерируемым (как Set или Map).
//строка
const arr = Array.from(‘дока’)
console.log(arr)
// [‘д’, ‘о’, ‘к’, ‘а’]
//объект Set
const uniqueNumbers = new Set()
uniqueNumbers.add(1)
uniqueNumbers.add(2)
uniqueNumbers.add(3)
const arr = Array.from(uniqueNumbers)
// [1, 2, 3]
Array.from() принимает три аргумента, второй - функция преобразования элемента перед его добавлением в массив. Работает как метод map(). третий - значение, которое будет использоваться как this в функции из второго параметра.
Вместо последовательного вызова Array.from() и .map():
const name = ‘Mike’
const spacedLetters = Array.from(name).map(function (letter) {
return *${letter}*
})
console.log(spacedLetters)
// [‘M’, ‘i’, ‘k’, ‘e’]
…можно записать один вызов Array.from() со вторым аргументом:
const name = ‘Mike’
const spacedLetters = Array.from(name, function(letter) { return *${letter}* })
При выполнении этого кода не создаётся промежуточный массив.!!!

65
Q

bind? call? apply?(методы ФУНКЦИЙ)

A

Это методы ФУНКЦИЙ. Все они привязывают контекст
bind возвращает другую функцию, которую необходимо еще и вызвать, чтобы функция запустилась с нужным контекстом.
call/apply сразу запускают функцию с нужным контекстом. call принимает параметры через запятую, apply принимает массив

66
Q

Задача для собесов: с setTimeout-ми на область видимости и замыкание

A
  1. Что будет в консоле? Как исправить данный результат на то, что предполагалось увидеть?

for(var i = 0; i<10; i++){
setTimeout(()=>{
console.log(i)
}, i*1000)
}
//будет вывод 10 каждую секунду 10 раз, т.к. цикл for синхронен и выполнится мгновенно, в отличие от таймаутов. var - глобальная переменная в данном случае(имеет функциональную область видимости, но здесь ее нет) и каждый раз она будет перезатираться новым значением(0 на 1, 2 на 3 и тд)
Таймауты запомнят ссылку на переменную i и когда придет время отрабатывать, то возьмет уже итоговую переменную i=10(проверяет, что 10 не меньше 10(10<10//false), но переменная уже 10). В итоге таймауты будут выводить итоговую переменную через каждую секунду.

Как исправить? либо var меняем на let, либо делаем замыкание:
for (var i = 0; i < 10; i++) {
(function (index) {
setTimeout(function () {
console.log(index);
}, index * 1000);
})(i);//самовызывается
}
//для каждой переменной i создаем новый контекст, где на нее будет ссылаться таймаут, который сидит в этой функции.
//результат- 1 2 3 4 5 6 7 8 9

//если бы применили let, то т.к. она имеет блочную область видимости, то сохранялась бы для каждого таймаута отдельно.

67
Q

Задача для собесов: счетчик(замыкание)

A

function makeCounter() {
var currentCount = 1
return function () {
return currentCount++
}
}

var counter = makeCounter()
//сounter - уже функ. выражение
// при вызове основной функции возвращает аноним функцию. Теперь она будет храниться в этой переменной.

alert(counter()) // 1
alert(counter()) // 2
alert(counter()) // 3
//теперь можем вызвать вернувшуюся функцию, которая сидит в переменной! Каждый раз при ее вызове результат будет увеличиваться

var counter2 = makeCounter()
//если вызвать основную функцию и положить ее в другую переменную, то это будет уже другая функция, независимая от первой.
alert(counter2()) // 1

Кстати! Чем отличается currentCount++ от ++currentCount?
currentCount++ - постфиксный оператор увеличивает значение переменной currentCount на единицу, но возвращает старое значение переменной, до того как оно было увеличено.(то есть вернет 1)
++currentCount - префиксный оператор также увеличивает значение переменной currentCount на единицу, но возвращает новое увеличенное значение.(то есть вернет уже 2)

68
Q

Задача для собесов: bind

A

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

  1. function foo() {
    console.log(this.name);
    }

let a = { name: ‘Dima’ };
let b = { name: ‘Viktor’ };

const bindedFooA = foo.bind(a);
const bindedFooB = foo.bind(b);
//связали функцию с другими контекстами, получили две другие функции с контекстами.

bindedFooA(); // ‘Dima’
bindedFooB(); // ‘Viktor’
//теперь вызываем ОБЯЗАТЕЛЬНО! эти новые функции.

  1. Более сложный пример с параметрами:

function foo(age, city) {
console.log(${this.name}, ${age}, ${city});
}

let a = { name: ‘Dima’ };
let b = { name: ‘Viktor’ };

const bindedFooA = foo.bind(a, 30);
const bindedFooB = foo.bind(b, 18);
//связали функцию с разными контекстами, получили две разные функции. Можем передать дальше аргументы, в нашем случае это попадем в age параметр…

bindedFooA(‘Tbilisi’); // Dima, 30, Tbilisi
bindedFooB(‘Minsk’); // ‘Viktor, 18, Minsk
//… вызвав новую функцию, можно еще и передать следующие аргументы! они пойдут следом за другими, которые были переданы в bind

69
Q

Что возвращает async ассинхронная функция?

A

То, что она ретурнет, это всегда промис!
Если в такой функции явно не прописан return, то промис также возвращается! только ее зарезолвенный результат будет равен undefined!

70
Q

Задача для собесов: apply/call

A

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

function foo(age, city) {
console.log(this.name, ${age}, ${city})
}

let a = { name: ‘Dima’ }
let b = { name: ‘Viktor’ }

foo.apply(a, [31, ‘Tbilisi’]) - массив
foo.call(b, 18, ‘Minsk’) - запятая
//привязываем контекст к функции и тут же сразу вызывают ее с новым контекстом. Отличие в передачи аргументов

71
Q

Задача для собесов: map, filter

A

map возвращает НОВЫЙ массив.
map нужен, чтобы из массива, в котором содержаться элементы в оригинальном виде, получить массив той же длины, который содержит “новые” элементы, полученные на основе элементов старого массива:
[‘1’, ‘2’, ‘3’].map((el) => +el) // массив строк преобразовываем в массив чисел
[18, 20, 12].map((age) => {
if (age >= 18) {
return { age: age, adult = true }
} else {
return { age, adult = false }
}
}) // из массива чисел получаем массив объектов, с полями: age и adult (взрослый): true\false в зависимости от того, возраст >= 18 или нет

filter возвращает НОВЫЙ массив.
filter нужен, чтобы получить новый отфильтрованный массив, в котором будет меньше элементов, чем в исходном, потому что мы фильтруем исходный, убираем ненужное:
[‘Minsk’, ‘Moscow’, ‘’, ‘’, ‘London’, ‘’].filter( (el) => el !== ‘’); // пропускам в результирующий массив не пустые строки
[{age: 18, sex: ‘f’, name: ‘Sveta’}, {age: 17, sex: ‘f’, name: ‘Sashka’}, {age: 19, sex: ‘m’, name: ‘Andrew’}].filter( (person) => {
return person.age >= 18 && person.sex === ‘f’;
}) // пропускаем на вечеринку только тех, кто девочка и кому 18+}

72
Q

Задача для собесов: reducer

A

reducer пробегается по всему массиву и на выход выдаёт какое-то одно обобщённое значение, которое всегда возвращаем(return). Это может быть как новый МАССИВ, так и простое значение примитив или ОБЪЕКТ:

Простой подсчет общего числа:
[‘Minsk’, ‘Moscow’, ‘’, ‘’, ‘London’, ‘’]
.reduce((acc, el) => {
if (el !== ‘’) acc++
return acc
}, 0) // подсчитываем, сколько у нас в массиве не пустых строк

Создание нового массива:
[
{ age: 18, sex: ‘f’, name: ‘Sveta’ },
{ age: 17, sex: ‘f’, name: ‘Sashka’ },
{ age: 19, sex: ‘m’, name: ‘Andrew’ }
].reduce((acc, person) => {
if (person.age >= 18 && person.sex === ‘f’) {
acc.push(person)
}
return acc
}, []) // на выходе получаем новый массив, состоящий из людей, кто девочка и кому 18+ (но лучше эту задачу решать с помощью filter, но и так можно)

Подсчет суммы:
[1, 4, 6, 66, -12].reduce((acc, number) => {
acc += number
return acc
}, 0) // подсчёт суммы всех чисел в массиве

73
Q

Задача для собесов: наследование, пример на class\extends

A

class Animal {
constructor(name) {
this.name = name
}
walk() {
alert(‘I walk: ‘ + this.name)
}
eat() {
alert(‘I can eat’)
}
}

class Rabbit extends Animal {
walk() {
super.walk()
alert(‘…and jump!’)
}
}

var rabbit = new Rabbit(‘Bunny’)
rabbit.walk()
rabbit.eat()
// 1 алерт - ‘I walk: Bunny’
// 2 алерт - ‘…and jump!’
// 2 алерт - ‘I can eat’

74
Q

setState принимает второй аргумент - коллбэк-функцию, для чего?

A

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

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

import React, { useState } from ‘react’;

const MyComponent = () => {
const [count, setCount] = useState(0);

const handleClick = () => {
// Обновляем состояние count
setCount(count + 1, () => {
// Коллбэк-функция вызовется после обновления состояния и перерисовки компонента
console.log(‘Count has been updated:’, count);
//выведется 1, а не 0.
//0 вывелось бы, если бы мы вызвали консоллог вне коллбэк-функции
});
};

return (
<div>
<h1>Count: {count}</h1>
<button onClick={handleClick}>Increment</button>
</div>
);
};

export default MyComponent;

Значение count, использованное в коллбэк-функции после setState, будет обновленное значение, а не предыдущее. Это происходит потому, что коллбэк-функция вызывается после завершения обновления состояния и перерисовки компонента.

Если написать console.log(‘Count has been updated:’, count); вне коллбэк-функции, то покажет старое значение. Это происходит потому, что функция setState является асинхронной, и обновление состояния может не произойти мгновенно. Поэтому, когда вы вызываете console.log сразу после setCount, оно выполнится до того, как состояние будет обновлено и перерисовка компонента будет завершена.
Отсюда еще и момент про ассинхронность seState, когда React объединяет несколько обновлений состояния в одно для оптимизации производительности.

75
Q

Задачи для собесов: Промисификация, setInterval, setTimeout

A

function doItAfter(seconds) {
let promise = new Promise((resolve, reject) => {
setInterval(() => {
resolve()
}, seconds * 1000)
})
return promise
}

doItAfter(2).then(() => {
console.log(“This will be logged after 2 seconds”);
});

//”This will be logged after 2 seconds” будет выведено через 2 секунды после вызова doItAfter(2).

76
Q

Что такое Hoisting(поднятие)?

A

Hoisting (поднятие) - это механизм в JavaScript, при котором объявления переменных и функций перемещаются в верхнюю часть своей области видимости перед выполнением кода.
Это касается переменной var и FD (кстати, оказывается let и const тоже поднимаются, но остаются недоступны до их фактической инициализации, это временная мертвая зона).

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

77
Q

Задачи для собесов: В массиве найти максимальное/минимальное число

A

const numbers = [1, 45, 66, 2, 4, 6, -2, -10, -100, 100]

let minValue = numbers[0]
//берем самое первое число из массива

for (let i = 0; i < numbers.length; i++) {
if (numbers[i] < (> - для макс.) minValue) {
minValue = numbers[i]
}
}
console.log(minValue)

78
Q

Задачи для собесов: рекурсия, факториал

A

Пример:
1! = 1
2! = 2 * 1 = 2
3! = 3 * 2 * 1 = 6
4! = 4 * 3 * 2 * 1 = 24
5! = 5 * 4 * 3 * 2 * 1 = 120
//это число, умноженное на “себя минус один”, затем на “себя минус два”, и так далее до 1.

function factorial(n) {
return n ? n * factorial(n - 1) : 1
}
alert(factorial(5)) // 120”

  1. Если n равно 0 или отрицательное число, функция вернет 1. Это базовый случай рекурсии, чтобы избежать бесконечного цикла.
  2. После достижения базового случая(n==0), все рекурсивные вызовы вернутся обратно, и каждый вызов вернет результат умножения n на результат предыдущего вызова (factorial(n - 1)).
    factorial(5) вернет 5 * factorial(4).
    factorial(4) вернет 4 * factorial(3).
    factorial(3) вернет 3 * factorial(2).
    factorial(2) вернет 2 * factorial(1).
    factorial(1) вернет 1 * factorial(0).
    factorial(0) вернет 1. //больше не будет вызовов

Теперь все рекурсивные вызовы будут развернуты обратно:
factorial(1) вернет 1 * 1 = 1.
//т.е. factorial(0)*factorial(1) и тд
factorial(2) вернет 2 * 1 = 2.
factorial(3) вернет 3 * 2 = 6.
factorial(4) вернет 4 * 6 = 24.
factorial(5) вернет 5 * 24 = 120.

Таким образом, результат функции будет равен произведению всех чисел от n до 1, что соответствует факториалу числа n.

Объяснение рекурсии : https://www.youtube.com/watch?v=rh1mP02NFoM

79
Q

Задачи для собесов: рекурсия, фибоначчи

A

Следующее число получается как сумма двух предыдущих.
Первые два числа равны 1, затем 2(1+1), затем 3(1+2), 5(2+3) и так далее: 1, 1, 2, 3, 5, 8, 13, 21….

function fib(n) {
return n <= 1 ? n : fib(n - 1) + fib(n - 2);
}
alert( fib(3) ); // 2
alert( fib(7) ); // 13
// fib(77); // не запускаем, подвесит браузер”

  1. Если n меньше или равно 1, функция вернет n. Это базовый случай рекурсии, чтобы избежать бесконечного цикла.
  2. Если n больше 1, функция выполнит два рекурсивных вызова fib(n - 1) и fib(n - 2). Таким образом, она вызывает себя с аргументами n - 1 и n - 2:
    При вызове fib(3) функция будет выполнена следующим образом:
    fib(3) вернет fib(2) + fib(1).
    fib(2) вернет fib(1) + fib(0).
    fib(1) вернет 1, так как это базовый случай.
    fib(0) вернет 0, так как это базовый случай.

Теперь все рекурсивные вызовы будут развернуты обратно:
fib(1) вернет 1.
fib(0) вернет 0.
fib(2) вернет 1 + 0 = 1.
fib(3) вернет 1 + 1 = 2.

80
Q

Задачи для собесов: рекурсия, Сумма n чисел

A

function sumTo(n) {
if (n == 1) return 1//условие окончания
return n + sumTo(n - 1)
}

alert(sumTo(100)) // 5050

sumTo(100) вернет 100 + sumTo(100 - 1)
sumTo(99) вернет 99 + sumTo(99 - 1)

Теперь все рекурсивные вызовы будут развернуты обратно:
sumTo(1) вернет 1.
sumTo(2) вернет 3.

81
Q

Задачи для собесов: написать метод flat самому. Применяется проверка каждого элемента является ли он массивов и плюс еще задействована рекурсия

A

const multArr=[1, [1,2, [3,4]], [2,4]]
//многомерный массив

const flatArr = (arr) =>{
let result = [ ]
//переменная, куда будем складывать результат

arr.forEach(el=>{
if(Array.isArray(el)){
result = […result, …flatArr(el)]
}else{
result = […result, el]
}
})
return result
}

console.log(flatArr(multArr))

//проходимся по каждом элементу массива и проверяем, что если элемент - массив, то в новую переменную result создаем новый массив, копируем содержимое этого массива, если оно есть и в него же вкладываем результат вызова этой же функции

82
Q

Что такое семантичность? Для чего script и какие атрибуты он имеет?

A

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

script позволяет подключать js-код, либо как отдельный файл через src, либо можно писать прямо в теге.
Есть два атрибута:
1. async, указывающий браузеру, запускать скрипт, указанный в атрибуте src, как только он подгрузился. Т.е. асинхронно
src должен быть, иначе не будет работать.
2. defer - атрибут, указывающий браузеру, что скрипт должен выполняться после разбора документа HTML.
src должен быть, иначе не будет работать.

83
Q

Что такое шаблон(шаблонная строка) и литерал?

A

Это способы создания строк и др. структур данных.

var singleQuoted = ‘Это строка в одинарных кавычках.’;
// литерал ({},[], и тд)

var name = ‘Иван’;
var greeting = Привет, ${name}! Как дела?;
//шаблонная строка

84
Q

Минусы копирования объекта через json, Object.assign() и spread

A

1.JSON-подобный метод:
ПРЕДПОЧТИТЕЛЬНЫЙ ИЗ ВСЕХ, делает глубокую копию почти для всех типов, не использовать для специфических типов!!!
var original = { a: 1, b: 2 };
var copy = JSON.parse(JSON.stringify(original));

//(JSON. parse() берет строку JSON и трансформирует ее в объект JavaScript.
// JSON. stringify() берет объект JavaScript и трансформирует его в строку JSON)

Минусы:
–Ограниченность типами данных: Он работает ТОЛЬКО с простыми типами данных, такими как строки, числа, булевы значения и ОБЪЕКТЫ. Нельзя сохранить ссылки на !!!специфичные объекты или классы!!!.
–Потеря функциональности: При стрингифайе объекта в строку JSON, все функции, методы и специальные свойства (например, функции обратного вызова) будут утеряны.

2.Object.assign():
var original = {
a: 1,
b: {
c: 2
}
};
var copy = Object.assign({}, original);
copy.b.c = 3; // Это изменит исходный объект тоже
Минусы:
–Поверхностное копирование - если есть вложенные объекты или объекты внутри массивов, они будут скопированы по ссылке, а не по значению.
–Он не копирует свойства объекта, которые определены с помощью геттеров и сеттеров.

  1. Spread:
    var original = { a: 1, b: { c: 2 } };
    var copy = { …original };
    copy.b.c = 3;
    // Это изменит исходный объект тоже

Минусы:
–Поверхностное копирование (для объектов): Подобно Object.assign(), оператор распространения выполняет поверхностное копирование объектов.
– Также работает и со вложенными массивами в массиве, копирует по ссылке

85
Q

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

A
  1. Использование библиотек:
    Существуют библиотеки, такие как Lodash, которые предоставляют функции для глубокого копирования объектов. Например, _.cloneDeep() из Lodash может быть использован для создания глубокой копии объекта.
    const _ = require(‘lodash’);

var original = { a: 1, b: { c: 2 } };
var copy = _.cloneDeep(original);

2.Использование стандартного метода JSON.parse(JSON.stringify(obj)) (нельзя клонировать сложные типы)

  1. Функция structuredClone, встроенная в среду выполнения JavaScript:

В отличии от других способов, например json, можно:
–клонировать широкий спектр типов JavaScript, таких как: Date, Set, Map, Error, RegExp, ArrayBuffer, Blob, File, ImageData и многие другие.

const kitchenSink = {
set: new Set([1, 3, 3]),
map: new Map([[1, 2]]),
regex: /foo/,
deep: { array: [ new File(someBlobData, ‘file.txt’) ] },
error: new Error(‘Hello!’)
}
kitchenSink.circular = kitchenSink

// ✅ Выполнено полное глубокое копирование
const clonedSink = structuredClone(kitchenSink)

  1. Рекурсивное копирование:
    Вы можете создать функцию, которая рекурсивно перебирает свойства объекта и копирует их. Если свойство объекта является объектом или массивом, функция будет рекурсивно копировать его.
    function deepCopy(obj) {
    if (obj === null || typeof obj !== ‘object’) {
    return obj;
    }// проверка что не null и что это объект

if (Array.isArray(obj)) {
return obj.map(deepCopy);
}//если массив то вызывается эта функция для КАЖДОГО элемента массива. Получается копирует вложенные массивы в массиве.

const copy = {};
for (const key in obj) {
//перебираем свойства объекта
if (obj.hasOwnProperty(key)) {
//метод hasOwnProperty() используется для проверки, что свойство действительно принадлежит obj, и что оно не унаследовано от его прототипа. Это важно для избежания нежелательного копирования унаследованных свойств.
copy[key] = deepCopy(obj[key]);
//создается копия свойства, а значение создается с помощью рекурсивного вызова функции deepCopy для значения, связанного с ключом key в объекте obj. Это позволяет глубоко скопировать значение свойства, включая вложенные объекты или массивы, если они есть.
}
}

return copy;
}

var original = { a: 1, b: { c: 2 } };
var copy = deepCopy(original);

86
Q

Как узнать что объект был создан через класс или функцию конструктор?

A

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

Но можно использовать некоторые признаки или проверки.

  1. Проверка наличия прототипа:
    Вы можете проверить наличие свойства constructor.prototype у объекта. Если это свойство существует и указывает на определенный конструктор (класс), то это может указывать на то, что объект был создан с использованием этого конструктора.

function Person(name) {
this.name = name;
}
const person = new Person(‘John’);

if (person.constructor.prototype === Person.prototype) {
console.log(‘Объект создан с использованием Person’);
}

2.Проверка instanceof:
Метод instanceof позволяет проверить, является ли объект экземпляром определенного класса (или функции-конструктора).
function Person(name) {
this.name = name;
}
const person = new Person(‘John’);

if (person instanceof Person) {
console.log(‘Объект является экземпляром Person’);
}

3.Проверка конструктора:
Вы можете проверить свойство constructor объекта и убедиться, что оно соответствует ожидаемому конструктору.
function Person(name) {
this.name = name;
}
const person = new Person(‘John’);

if (person.constructor === Person) {
console.log(‘Объект создан с использованием Person’);
}

87
Q

Дебаунс(Debouncing) и троттлинг (Throttling)(отличие)?

A

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

Троттлинг функции означает, что функция вызывается не более одного раза в указанный период времени (например, раз в 10 секунд). Другими словами ― троттлинг предотвращает запуск функции, если она уже запускалась недавно.
Троттлинг также обеспечивает регулярность выполнение функции с заданной периодичностью.
Throttling ограничивает частоту выполнения функции, обеспечивая, чтобы она не выполнялась слишком часто. Например, если у вас есть функция, которая реагирует на прокрутку страницы, Троттлинг может гарантировать, что эта функция будет вызываться не чаще определенного интервала времени.

Дебаунс (Debouncing):
Debouncing функции означает, что все вызовы будут игнорироваться до тех пор, пока они не прекратятся на определённый период времени. Только после этого функция будет вызвана. Например, если мы установим таймер на 2 секунды, а функция вызывается 10 раз с интервалом в одну секунду, то фактический вызов произойдёт ТОЛЬКО спустя 2 секунды ПОСЛЕ крайнего (десятого) обращения к функции.
Пример:
Автозаполнение. Предположим, вы вводите в строку поиска «Greenwich». API автозаполнения будет вызываться при изменении текста в строке поиска. Если бы не debouncing, вызов API выполнялся бы после каждой введённой буквы, даже если вы печатаете очень быстро. Проблема в том, что нет гарантии, что API запросы будут возвращены в том порядке, в котором они были отправлены. Например, запрос автозаполнения для «Gre» может вернуться после запроса для «Green».
Поэтому имеет смысл «притормозить» поиск. Debouncing функции автозаполнения на одну секунду позволит ограничить запросы, пока пользователь не перестанет печатать.

Можно провести такую аналогию:
Предположим, вы работаете за компьютером и в то же время чатитесь с другом в мессенджере, который отправляет вам сообщение за сообщением. Вы получаете пуш уведомления каждую минуту. В обычном случае вы бы прочитывали эти сообщения сразу, но сейчас вы заняты и не можете так часто отвлекаться. Как можно поступить?
1. Игнорировать уведомления, и прочитывать принятые сообщения раз в пять минут.
2. Игнорировать уведомления. Если в течение последних пяти минут не поступало новых уведомлений, предположим, что друг закончил свою историю и тогда проверить принятые сообщения.
Первый вариант можно сравнить с throttling, а второй с debouncing.

https://medium.com/nuances-of-programming/%D1%87%D1%82%D0%BE-%D1%82%D0%B0%D0%BA%D0%BE%D0%B5-throttling-%D0%B8-debouncing-4f0a839769ef

88
Q

Utility Types в TS

A

“утилитарные типы”
Pick, Partial, Omit, Required, Readonly<Type>(доступны только для чтения ),
Exclude<Type, ExcludedUnion> и Extract<Type, Union>:
Exclude и Extract позволяют извлекать или исключать типы из объединений типов.</Type>

type Color = ‘red’ | ‘green’ | ‘blue’;
type PrimaryColor = ‘red’ | ‘blue’;

type NonPrimaryColor = Exclude<Color, PrimaryColor>; // ‘green’ - исключили
// NonPrimaryColor теперь равен ‘Red’ | ‘Blue’
type PrimaryColors = Extract<Color, PrimaryColor>; // ‘red’ | ‘blue’ - извлекли
// PrimaryColors теперь равен ‘red’ | ‘blue’

89
Q

Веса селекторов

A

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

От низшего к наивысшему:

Тип селектора (например, div, p, h1) имеет самый низкий вес. Он применяется к элементам соответствующего типа.

Селектор класса и селектор атрибута:
Селекторы класса (например, .example) и селекторы атрибута (например, [data-attribute]) имеют средний вес. Они более специфичны, чем типовые селекторы, но менее специфичны, чем селекторы идентификаторов.

Селектор идентификатора:
Селектор идентификатора (например, #uniqueId) имеет более высокий вес по сравнению с селекторами классов и типами. Идентификаторы должны быть уникальными на странице, поэтому они имеют больший приоритет.

Селектор псевдокласса и селектор псевдоэлемента:
Селекторы псевдокласса (например, :hover, :focus) и селекторы псевдоэлемента (например, ::before, ::after) могут иметь разный вес в зависимости от их специфичности.

!important:
Свойства, помеченные ключевым словом !important, имеют высший приоритет и переопределяют все предыдущие стили, даже если они менее специфичны.

Инлайн-стили:
Инлайн-стили, определенные непосредственно в HTML элементе с использованием атрибута style, имеют наивысший приоритет и переопределяют все другие стили.

90
Q

Что нового в последнем ECMAScript?
Что нового привнес в JS стандарт ES6?

A

Что нового в последнем ECMAScript?

Метод String.prototype.replaceAll():
Этот метод позволяет заменить все вхождения подстроки в строке на другую подстроку без необходимости использования регулярных выражений. Он делает замену глобальной и без учета регистра.
const originalString = “Hello, world!”;
const newString = originalString.replaceAll(“l”, “L”);
console.log(newString); // “HeLLo, worLd!”

Метод Promise.any():
Promise.any() позволяет выполнить несколько промисов и вернуть первый промис, который завершится успешно. Если все промисы завершатся с ошибкой, то будет возвращен объект AggregateError, содержащий информацию обо всех ошибках.

Part of the ECMAScript 2023 standard:
.toReversed():
Метод .toReversed() переворачивает массив, при этом не мутируя его, создавая новый массив. Старый метод .reverse() мутирует массив, не создает новый.

.toSorted():
Метод .toSorted() сортирует элементы массива, при этом не мутируя его, создавая новый массив. Старый метод .sort() мутирует массив, не создает новый.

.toSpliced():
Метод .toSpliced() удаляет необходимые элементы массива, при этом не мутируя его, создавая новый массив. Старый метод .splice() мутирует массив, не создает новый.
const numbers = [1, 2, 3];
const splicedNumbers = numbers.toSpliced(1, 1);

console.log(splicedNumbers); // Output[1, 3]

Что нового привнес в JS стандарт ES6?

Стрелочный функции, классы, шаблонные строки, деструктуризация, операторы ….rest/…spread, Symbol, Генераторы, Блочная область видимости.
Промисы, модули, прокси, множества Set/Map.
Расширенные объектные литералы.

(оператор ….rest
собирает оставшиеся элементы массива в другой массив или собирает оставшиеся свойства объекта в другой объект. Он всегда идёт последним и может использоваться только раз при одной операции «распаковки» массива или объекта. В React оператор rest используется для работы с пропсами в компонентах.
Пример:
function MyComponent({ title, description, …rest }) {

return (
<div>
<h1>{title}</h1>
<p>{description}</p>
<ChildComponent {…rest} />
</div>
);
}
)

91
Q

Critical Rendering Path,что будет когда в URL введешь адрес и нажмешь enter

A

Critical Rendering Path (CRP) - это концепция, связанная с процессом рендеринга веб-страницы в браузере. Когда вы вводите URL-адрес в адресной строке браузера и нажимаете клавишу Enter, происходит следующий процесс в контексте CRP:

Навигация:
Браузер начинает процесс навигации, запросив указанный URL-адрес. Это включает в себя отправку запроса к серверу, получение ответа и загрузку необходимых ресурсов, таких как HTML, CSS, JavaScript и изображения.

Создание DOM (Document Object Model):
По мере загрузки HTML-документа браузер начинает создавать DOM, представляющий структуру веб-страницы. DOM - это древовидное представление HTML-документа, которое браузер использует для построения веб-страницы.

Построение CSSOM (CSS Object Model):
В то время как браузер загружает CSS-файлы, он начинает построение CSSOM, представляющего стили страницы. CSSOM - это древовидное представление стилей, которое соответствует DOM.

Формирование Render Tree:
После того как DOM и CSSOM созданы, браузер комбинирует их, чтобы создать Render Tree. Render Tree - это древовидное представление страницы, которое содержит информацию о том, как каждый элемент будет отображаться на экране, включая их размеры, позицию и стили.

Расчет Layout:
Браузер производит расчет макета (layout), определяя размеры и позиции каждого элемента на странице в соответствии с Render Tree. Это определяет, как элементы будут располагаться относительно друг друга.

Рендеринг Paint:
Затем браузер начинает процесс рендеринга (painting), который включает в себя настоящую отрисовку пикселей на экране в соответствии с макетом и стилями. Это создает окончательное изображение веб-страницы.

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

92
Q

requestAnimationFrame

A

создание анимации на JavaScript, через функцию requestAnimationFrame.

По большому счету существует два способа, как сделать анимацию на JS:
-через методы setTimeout, setInterval
-через функцию requestAnimationFrame

setTimeout, setInterval:
Частота кадров на мониторе и частота перерисовки браузером контента может быть не постоянной, это зависит от нагрузки, сколько одновременно запущено программ на компьютере клиента.
В таких случаях можно наблюдать, как какие-то кадры замирают.
Происходит рассинхронизация: setTimeout принуждает перерисовывать кадры, не синхронно со сменой кадров у компьютера. Однако самая большая проблема состоит в том, что если открыто несколько вкладок браузера, и на одной из них есть анимация, то она все равно работает, активна эта вкладка или нет. В результате, все это ведет к избыточной нагрузке на компьютер.

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

https://frontender.info/request-animation-frame-for-better-performance/

93
Q

атрибуты role, aria (HTML)

A

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

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

Вот некоторые примеры использования атрибута role:
–role=”button”: Если у вас есть элемент, который выглядит как кнопка, но не является элементом <button>, вы можете добавить role=”button”, чтобы указать, что этот элемент выполняет функцию кнопки. Это важно для пользователей, которые используют средства ассистивных технологий, такие как скрин-ридеры, чтобы понять, что элемент можно нажимать.</button>

<div>Нажми меня</div>

–role=”list” и role=”listitem”: Для списков и их элементов можно использовать соответствующие роли, чтобы указать структуру и связи между ними.

<ul>
<li>Элемент 1</li>
<li>Элемент 2</li>
</ul>

–role=”alert”: Для уведомлений или сообщений об ошибках можно использовать role=”alert”, чтобы сообщить пользователям о важной информации.

<div>Ошибка: Неверный пароль</div>

–role=”region”: Для выделения области на странице, такой как боковая панель, которая может содержать содержимое с обособленной функциональностью, вы можете использовать role=”region”.

<div>
<!-- Содержание боковой панели -->
</div>

!!!!В первую очередь используйте роли для семантически нейтральных тегов — <div> или <span>.!!!! У многих семантических HTML-тегов уже есть встроенные роли.</span>

Чтобы правильно использовать роли на практике, полезно разобраться с их типами. В ARIA есть шесть типов ролей и их значений соответственно:
роли виджетов;
роли структуры документа;
роли ориентиров;
роли изменяющихся областей (live regions);
роли окон;
абстрактные роли.

Здесь описаны все роли всех 6 типов:
https://doka.guide/a11y/aria-roles/

  1. aria-атрибуты
    Некоторые из основных целей aria-атрибутов включают:
    —Предоставление семантики: aria-атрибуты позволяют разработчикам добавлять дополнительную семантику к элементам, которая может быть неочевидной из HTML-кода. Например, они могут указывать роль элемента (например, aria-button, aria-menu, aria-alert) или состояние элемента (например, aria-expanded, aria-checked).
    —Атрибуты ARIA позволяют сделать более сложные интерактивные элементы, такие как кастомные кнопки, меню и вкладки, доступными для всех пользователей, включая тех, которые используют ассистивные технологии.

Примеры:
—aria-label. Если на нашем сайте меню сделано с помощью иконок, а не текста, скринридер может их не прочитать.
Атрибут aria-label позволяет добавить невидимую подпись любому элементу — она не появится на экране, зато скринридер легко прочитает, что там написано.
<img></img>
—aria-keyshortcuts. Некоторые элементы интерфейса могут быть привязаны к горячим клавишам. Чтобы скринридер мог сообщить пользователю, что у текущего элемента есть своя горячая клавиша для быстрого перехода или активации, используют атрибут aria-keyshortcuts. В нём указывают сочетания клавиш без дополнительных пояснений, чтобы скринридер мог их правильно озвучить:
<button>Кнопка</button>
—aria-disabled. Когда пользователь на странице нажимает клавишу Tab, он по очереди переключается между интерактивными элементами — кнопками, ссылками, пунктами меню, полями ввода и так далее. Но если кнопка сейчас недоступна для нажатия, скринридер её пропустит. Такое бывает, когда мы, например, не заполнили форму ввода — кнопка станет активной только после заполнения всех полей.
Если мы добавим свойство aria-disabled такой кнопке, то скринридер её увидит и тоже сможет озвучить, добавив, что нажать на неё пока нельзя. Это нужно для того, чтобы пользователь понял — кнопка на странице есть, но пользоваться ей пока не получится.
<button>Подписаться</button>
—aria-required. Когда мы создаём, например, форму подписки, у нас есть обязательные поля — имя и адрес электронной почты. Мы привыкли, что обязательные поля помечаются звёздочкой, но при чтении иногда это бывает неочевидно.
Если мы хотим сообщить скринридеру, что перед ним — обязательное поле, то к нему добавляется атрибут aria-required:
<input></input>

Примеры всех aria-атрибутов:
https://doka.guide/a11y/aria-attrs/

94
Q

SEO: зачем нужен robots.txt, noindex, nofollow и sitemap.xml

A

robots.txt, noindex, nofollow, и sitemap.xml являются инструментами, связанными с поисковой оптимизацией и управлением поведением поисковых систем на веб-сайте. Вот их основные цели и назначения:

robots.txt:

Цель: robots.txt - это текстовый файл, размещенный на сервере веб-сайта, который указывает поисковым роботам (краулерам), какие страницы и разделы сайта следует или не следует индексировать.
Применение: С помощью robots.txt вы можете запретить поисковым системам индексацию конкретных частей сайта или отдельных файлов. Например, вы можете запретить индексацию страниц с личной информацией или тестовыми данными.
noindex и nofollow:

Цель: noindex и nofollow - это мета-теги <meta></meta>, которые можно добавить на отдельные страницы HTML для указания поисковым системам, следует ли индексировать страницу (noindex) и следует ли следовать ссылкам с этой страницы (nofollow).
Применение: Вы можете использовать noindex, чтобы исключить конкретные страницы из индекса поисковых систем. nofollow позволяет управлять тем, следует ли краулерам переходить по ссылкам на этой странице. Это может быть полезно, чтобы предотвратить индексацию или проходку “страниц-мостиков” или “страниц-ловушек”.
sitemap.xml:

Цель: sitemap.xml - это XML-файл, который содержит информацию о структуре и содержании вашего веб-сайта. Он предоставляет поисковым системам дополнительные данные о страницах, которые можно индексировать.
Применение: sitemap.xml используется для улучшения процесса индексации поисковыми системами. Он может включать в себя ссылки на страницы сайта, которые поисковые роботы могли бы упустить. Это помогает поисковым системам более эффективно сканировать и индексировать сайт.

95
Q

что такое микроразметка (breadcrumbs, article, faq и тд)

A

Микроразметка (Microdata) - это формат разметки данных на веб-страницах с целью предоставления дополнительной информации поисковым системам о содержании страницы.

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

Вот некоторые типы микроразметки:
—Микроразметка “Breadcrumbs” (хлебные крошки):
Используется для указания структуры навигации на веб-сайте. Это позволяет поисковым системам понимать, какие страницы находятся внутри каких разделов сайта и как пользователи могут навигировать по сайту.
—Микроразметка “Article” (статья):
Помогает определить, что на странице находится статья, и предоставляет информацию о заголовке, авторе, дате публикации и тексте статьи. Это помогает поисковым системам выделять статьи и отображать их более выразительно в результатах поиска.
—Микроразметка “FAQ” (часто задаваемые вопросы):
Используется для структурирования данных в разделе с часто задаваемыми вопросами и ответами. Это позволяет поисковым системам понимать, что страница содержит FAQ и какие вопросы и ответы в ней представлены.
—-Микроразметка “Product” (товар):
Предоставляет информацию о продуктах, такую как название, цена, наличие, описание и многое другое. Это особенно полезно для интернет-магазинов, так как помогает поисковым системам выделить информацию о продуктах в результатах поиска.
—Микроразметка “Local Business” (местный бизнес):
Используется для предоставления информации о местных компаниях, включая название, адрес, телефон, часы работы и другие данные. Это помогает улучшить видимость местного бизнеса в локальных результатах поиска.

Микроразметка часто реализуется с использованием структурированного формата, такого как Schema.org, который определяет стандарты для разметки данных. Она может быть добавлена к HTML-коду страницы в виде специальных атрибутов и значений, которые соответствуют конкретным типам микроразметки.
Важно правильно реализовывать микроразметку, чтобы она была понятной для поисковых систем и способствовала улучшению видимости вашего контента в результатах поиска.

Пример микроразметки “Article”:
<!DOCTYPE html>

<html>
<head>
<title>Пример статьи с микроразметкой</title>
</head>
<body>
<!-- Микроразметка для статьи -->
<article>
<h1>Заголовок статьи</h1>
<p>Автор: <span>Иван Иванов</span></p>
<p>Дата публикации: <span>2023-10-30</span></p>
<div>
<p>Содержание статьи...</p>
</div>
</article>
</body>
</html>

В этом примере мы использовали микроразметку Schema.org для определения структуры статьи. Здесь itemscope обозначает, что это элемент с микроразметкой, и itemtype указывает на тип микроразметки (Article).

Затем мы используем itemprop для свойств статьи. Например, headline указывает на заголовок статьи, author указывает на автора, datePublished указывает на дату публикации, и articleBody указывает на сам текст статьи.

96
Q

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

A

null обозначает отсутствие значения. Это специальное значение, которое указывает, что переменная существует, но её значение пока не определено. Например, когда вы явно присваиваете переменной null, это означает, что она является пустой или неопределенной.

undefined обозначает, что значение переменной не было присвоено или переменная была объявлена, но ей не было присвоено значение. Если переменная не была инициализирована, то её значение по умолчанию будет undefined.

let a; // переменная a сейчас undefined, потому что ей не было присвоено значение
let b = null; // переменная b имеет значение null

Одна из основных различий между ними заключается в их типах данных: null является объектом, в то время как undefined является типом данных.
console.log(typeof null); // “object”
console.log(typeof undefined); // “undefined”

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

97
Q

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

A

1 способ. Есть у каждого объекта метод hasOwnProperty(), параметром передается свойство искомое, если оно есть вернется true
2 способ. Использовать оператор in , вернет true, если есть свойство.

Отличие их в том, что оператор in проверяет наличие свойства не только в самом объекте, но и в его прототипах, а hasOwnProperty() только в объекте

98
Q

псевдоложь

A

false, null, NaN, undefined, ‘’, 0, BigInt(0)

99
Q

Что такое деструктуризация

A

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

100
Q

какие есть способы работы с асинхронным кодом

A
  1. Callbacks:
    Функции передаются в качестве аргументов других функций и вызываются по завершении асинхронной операции.
    Пример:
    function fetchData(callback) {
    // Асинхронная операция
    setTimeout(() => {
    callback(‘Data received’);
    }, 1000);
    }

function processData(data) {
console.log(data);
}

fetchData(processData);

  1. Промисы (Promises):
    Объекты, представляющие успешное или отклоненное выполнение асинхронной операции.
  2. async/await:
    Синтаксический сахар над промисами, позволяющий писать асинхронный код в более линейном стиле.
101
Q

что такое распостранение события event propagation

A

Распространение событий (Event Propagation) в JavaScript описывает процесс, при котором браузер передает события от элемента, на котором они произошли, к его родительским или дочерним элементам в DOM.

Три фазы распространения событий по порядку!:
Фаза захвата (Capturing Phase):
–Событие передается от самого верхнего элемента в DOM к элементу, на котором произошло событие.
Фаза цели (Target Phase):
–Событие достигает целевого элемента, на котором оно произошло.
Целевое элемент - event.target.
Фаза всплытия (Bubbling Phase):
–Событие начинает “всплывать” от целевого элемента к самому верхнему элементу в DOM.

События двигаются от корневого к целевому(event.target) и обратно.
По умолчанию все события будут ловиться на фазе всплытия!!!, но по требованию событие можно отловить и на фазе погружения с помощью третьего параметра(useCapture ) в значении true метода addEventListener(‘…’, ()=>{}, true).

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

Отличия между event.target и event.currentTarget:
—-event.target указывает на элемент, на котором произошло событие (тот элемент, который фактически вызвал событие).
Например, при клике на дочерний элемент внутри родительского, event.target будет указывать на этот дочерний элемент.
Это свойство показывает именно тот элемент, который вызвал событие.
—–event.currentTarget указывает на элемент, на котором был установлен обработчик события (тот элемент, к которому был привязан обработчик события).
Например, если у вас есть вложенные элементы с обработчиками событий на родительском элементе, event.currentTarget будет указывать на родительский элемент, к которому был привязан обработчик события, даже если событие произошло на его дочернем элементе.

Метод stopPropagation() используется для прекращения дальнейшего распространения события. Если вызвать event.stopPropagation(), событие не будет передаваться дальше по DOM.

102
Q

делегирование события

A

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

На пример игры крестики-нолики, мы навешиваем событие на родителя, например,
const playSpace = document.getElementById(“playSpace”);
playSpace.addEventListener(“click”, handlerClick);

где в коллбеке происходит проверка на нужный id ячейки с помощью e.target, который написан у родителя. (e.target - будет то, на что мы кликнули)
const handlerClick = (e) => {
const cell = e.target;
// делегируем событие - исключаем все клики не относящиеся к нашим ячейкам
if (cell.getAttribute(“name”) !== “cell”) return;
const cellSymbol = stepPlayer();
cell.innerHTML = cellSymbol;
};

103
Q

в чем отличия event.preventDefault() от event.stopPropagation()

как узнать об использовании метода event.preventDefault()

A

event.preventDefault - отключает поведение элемента по умолчанию. Например, используем на элементе form, то он предотвратит отправку формы submit.

event.stopPropagation - отменяет распостранение события - всплытие или погружение

Чтобы узнать можно использовать свойство event.defaultPrevented, которое возвратит логическое значение, служащее индекатором применения к элементу метода event.preventDefault().

104
Q

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

A

—-Чаще всего используются в качестве коллбэков.
Передача функции в качестве аргумента в другие функции, такие как setTimeout, addEventListener, map, filter, reduce и другие.

—-Коллбэки событий: Например, когда вы назначаете обработчики событий.

—-Асинхронные операции: При использовании промисов, для обработки .then или .catch.
somePromise.then(function(result) {
console.log(‘Результат:’, result);
}).catch(function(error) {
console.error(‘Ошибка:’, error);
});

—-Краткосрочные функции: Если функция используется в узком контексте и не планируется повторное использование, можно использовать анонимные функции.

—-Контексты this: При необходимости зафиксировать контекст this, так как анонимные функции не создают собственный контекст this.
const myObject = {
value: 42,
printValue: function() {
setTimeout(() => {
console.log(this.value); // this ссылается на myObject
}, 1000);
}
};

105
Q

для чего используется директива use strict и какие ограничения она накладывает

A

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

  1. Избегание использования неявных глобальных переменных:
    Без “use strict” неявные объявления переменных (не используя var, let или const) создают глобальные переменные. В строгом режиме это запрещено.
  2. Запрет на удаление свойств объектов: В строгом режиме оператор delete не может удалять свойства объектов.
  3. Запрет на дублирование параметров функции: Нельзя дублировать параметры функции.
  4. this в функциях: В строгом режиме this в глобальной области видимости равен undefined.
  5. Сокрытие eval и arguments в локальной области видимости: Переменные с именами eval и arguments не могут быть переопределены.
106
Q

что такое функциональное программирование и какие особенности js позволяют говорить о нем как о функциональном языке

A

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

JavaScript, хотя и не является чистым функциональным языком программирования, обладает рядом функциональных особенностей:
1.Функции первого класса:
Функции в JavaScript могут быть переданы в качестве аргументов другим функциям, возвращены из функций или присвоены переменным. Это делает функции “первого класса”, что является основой для функционального стиля программирования.
2.Замыкания (Closures):
Возможность функции использовать переменные из окружающего контекста создает замыкания, что делает их мощным инструментом для функционального программирования.
3.Функции высшего порядка:
Возможность передавать функции в качестве аргументов и возвращать их из других функций позволяет создавать функции высшего порядка.
4.Методы массивов:
JavaScript предоставляет ряд методов для работы с массивами, таких как map, filter, reduce, которые позволяют использовать функциональный подход к обработке данных.
5.Иммутабельность и неизменяемость данных:
В JavaScript есть объекты и структуры данных, которые можно рассматривать как неизменяемые (например, const, Object.freeze). Это способствует функциональному стилю программирования, минимизируя побочные эффекты.

107
Q

почему функции в js называются объектами первого класса First-class Objects

A

Термин “объекты первого класса” (First-class Objects) означает, что функции в языке программирования рассматриваются так же, как и любые другие объекты (или значения) и могут быть переданы в качестве аргументов другим функциям, возвращены из функций, присвоены переменным, сохранены в структурах данных и т. д.

Когда функции считаются объектами первого класса, это означает, что они обладают следующими свойствами:

Могут быть присвоены переменным: Функцию можно сохранить в переменной.

Могут быть переданы в качестве аргументов: Функции могут быть переданы в другие функции в качестве аргументов.

Могут быть возвращены из других функций: Функции могут возвращать другие функции.

Могут быть сохранены в структурах данных: Функции могут быть частью объектов, массивов или других структур данных.

108
Q

Как создать объект не имеющий прототипа

A

Это можно сделать с помощью Object.create()
const obj = Object.create(null)
т.е. в качестве первого параметра передается методу этому объект-прототип

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

Так как null является примитивом, у него нет своего прототипа, и он не имеет методов, поскольку он не является объектом. Например, у null не будет методов, которые присутствуют у объектов, таких как toString() или valueOf().

Когда мы обращаемся к свойствам null, то такое обращение будет приводить к ошибке, поскольку null не имеет прототипа, который мог бы предоставить эти свойства или методы.

108
Q

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

A

Используется в функциях-конструкторах для создания нового экземпляра класса.

Делает 4 вещи:
–Создает пустой объект.
–Привязывает к нему значение this
–Функция наследует от function.prototype
–Возвращает значение this

109
Q
A

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

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

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

110
Q

что такое объектная обертка Wrapper object

A

Примитивы строка число и булеан имеют свойства и методы , несмотря на то, что они не являются объектами.
Когда вызываем методы для этих примитивов, они преобразуются в объект. У каждого примитива, кроме null/undefined, есть объект-обертка. Такими объектами являются String Number Boolean Symbol.

111
Q

в чем разница между явным и неявным преобразованием или приведением к типу

A

Неявное - способ приведения значения к другому типу без нашего ведома, например, складываем строку с числом

Явное - сами участвуем к преобразованию.

112
Q

почему typeof null возвращает object и как поверить является ли значение null

A

typeof null возвращает ‘object’, это историческая ошибка в JavaScript, которая сохраняется изначально для обратной совместимости. null - это примитив, но typeof null возвращает ‘object’.

Чтобы проверить, является ли значение null, можно использовать строгое сравнение (===)

113
Q

структуры Map Set

A

Map – это коллекция ключ/значение, как и Object. Но основное отличие в том, что 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 – возвращает текущее количество элементов.
Пример:
let map = new Map();
map.set(“1”, “str1”); // строка в качестве ключа
map.set(1, “num1”); // цифра как ключ
map.set(true, “bool1”); // булево значение как ключ
// помните, обычный объект Object приводит ключи к строкам?
// Map сохраняет тип ключей, так что в этом случае сохранится 2 разных значения:
alert(map.get(1)); // “num1”
alert(map.get(“1”)); // “str1”
alert(map.size); // 3

Map может использовать объекты в качестве ключей.
let john = { name: “John” };
// давайте сохраним количество посещений для каждого пользователя
let visitsCountMap = new Map();
// объект john - это ключ для значения в объекте Map
visitsCountMap.set(john, 123);
alert(visitsCountMap.get(john)); // 123
NaN также может использоваться в качестве ключа.

Для перебора коллекции Map есть 3 метода:
map.keys() – возвращает итерируемый объект по ключам,
map.values() – возвращает итерируемый объект по значениям,
map.entries() – возвращает итерируемый объект по парам вида [ключ, значение], этот вариант используется по умолчанию в for..of.
// перебор по значениям (числа)
for (let amount of recipeMap.values()) {
alert(amount); // 500, 350, 50
}

Кроме этого, Map имеет встроенный метод forEach:
// выполняем функцию для каждой пары (ключ, значение)
recipeMap.forEach((value, key, map) => {
alert(${key}: ${value}); // огурец: 500 и так далее
});

Если у нас уже есть обычный объект, и мы хотели бы создать Map из него, то поможет встроенный метод Object.entries(obj), который получает объект и возвращает массив пар ключ-значение для него, как раз в этом формате.
let obj = {
name: “John”,
age: 30
};
let map = new Map(Object.entries(obj));
alert( map.get(‘name’) ); // John
Здесь Object.entries возвращает массив пар ключ-значение: [ [“name”,”John”], [“age”, 30] ]. Это именно то, что нужно для создания Map.

Есть метод Object.fromEntries, который делает противоположное: получив массив пар вида [ключ, значение], он создаёт из них объект:
let prices = Object.fromEntries([
[‘banana’, 1],
[‘orange’, 2],
[‘meat’, 4]
]);
// prices = { banana: 1, orange: 2, meat: 4 }
alert(prices.orange); // 2

Объект 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.add() с одним и тем же значением ничего не происходит, за счёт этого как раз и получается, что каждое значение появляется один раз.

Например, мы ожидаем посетителей, и нам необходимо составить их список. Но повторные визиты не должны приводить к дубликатам. Каждый посетитель должен появиться в списке только один раз.
let set = new Set();

let john = { name: “John” };
let pete = { name: “Pete” };
let mary = { name: “Mary” };

// считаем гостей, некоторые приходят несколько раз
set.add(john);
set.add(pete);
set.add(mary);
set.add(john);
set.add(mary);

// set хранит только 3 уникальных значения
alert(set.size); // 3

for (let user of set) {
alert(user.name); // John (потом Pete и Mary)
}

Тоже самое мы могли бы сделать и с помощью массива + arr.find, но в этом случае бы пробегались бы по всем элементам массива, что значительно хуже по производительности, чем с Set. Множество Set лучше оптимизировано для добавлений, оно автоматически проверяет на уникальность.

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

Мы можем перебрать содержимое объекта set как с помощью метода for..of, так и используя forEach:
let set = new Set([“апельсин”, “яблоко”, “банан”]);
for (let value of set) alert(value);
// то же самое с forEach:
set.forEach((value, valueAgain, set) => {
alert(value);
});

Перебор Map и Set всегда осуществляется в порядке добавления элементов, так что нельзя сказать, что это – неупорядоченные коллекции, но поменять порядок элементов или получить элемент напрямую по его номеру нельзя.

114
Q

какие этапы отрисовки есть у страницы браузера? Как браузер рисует страницы

A

https://doka.guide/tools/how-the-browser-creates-pages/

Чтобы нарисовать на экране результат работы нашего кода, браузеру нужно выполнить несколько этапов:

  1. Сперва ему нужно скачать исходники.
  2. Затем их нужно прочитать и распарсить.
  3. После этого браузер приступает к рендерингу — отрисовке.

Рассмотрим подробнее эти этапы:

  1. Получение ресурсов, Fetching.
    Ресурсы браузер получает с помощью запросов к серверу. В ответ он может получить как, например, данные в виде JSON, так и картинки, видео, файлы стилей и скриптов.
    Самый первый запрос к серверу — обычно запрос на получение HTML-страницы (чаще всего index.html).
    В её коде содержатся ссылки на другие ресурсы, которые браузер тоже запросит у сервера, например, файл стилей style.css; изображение hello.jpg; и скрипт index.js.
  2. Парсинг, Parsing.
    Он состоит из 3х этапов:
    —формирование DOM
    —формирование CSSOM
    —Render Tree - объединение дом и стилей
    По мере того как скачивается HTML-страница, браузер пытается её «прочитать» — распарсить.
    Браузер работает не с текстом разметки, а с абстракциями над ним. Одна из таких абстракций, результат парсинга HTML-кода, называется DOM.
    Пока браузер парсит документ и строит DOM, он натыкается на элементы типа <img></img>, <link></link>,
    , которые содержат ссылки на другие ресурсы.
    Если ресурс неблокирующий (например, изображение), браузер запрашивает его параллельно с парсингом оставшейся части документа. Блокирующие ресурсы (например, скрипты) приостанавливают обработку(парсинг) до своей полной загрузки.
    Если скрипт стоит ДО тега, который еще не успел распарсить браузер, и в этом скрипте он как-то модифицируется, то в этом случае image === undefined, потому что браузер успел распарсить только часть документа до этого тега
    .
    Если скрипт поставить ПОСЛЕ тега, то изображение найдется.
    Есть атрибуты, который скажут браузеру как поступить, например, атрибут defer скажет браузеру продолжать парсить страницу и выполнить скрипт потом, даже если скрипт стоит ДО тега.
    Когда браузер находит элемент <link></link>, который указывает на файл стилей, браузер скачивает и парсит его. Результат парсинга CSS-кода — CSSOM.
    CSSOM (CSS Object Model) — по аналогии с DOM, представление стилевых правил в виде дерева. тег=>стиль
    Чтение стилей приостанавливает чтение кода страницы. Поэтому рекомендуется в самом начале отдавать только критичные стили — которые есть на всех страницах и конкретно на этой. Так мы уменьшаем время ожидания, пока «страница загрузится».
    Благодаря оптимизациям (например, сканеру предзагрузки) стили могут не блокировать чтение HTML, но они точно блокируют выполнение JavaScript, потому что в JS могут использоваться CSS-селекторы для выборки элементов.
    Render Tree:
    После того как браузер составил DOM и CSSOM, он объединяет их в общее дерево рендеринга — Render Tree.
    В итоге получаем объединенное дерево:
    HTML => <body/> со стилями => <img></img> со стил. или например
    HTML => <body/> со стилями => .text со стилями => 'Hello World!'
    //естественно, от боди или других тегов может быть много разветвлений, отсюда и название Дерево.
    Обратите внимание, что в Render tree попадают только видимые элементы. Если бы у нас был элемент, спрятанный через display: none, он бы в это дерево не попал.
  3. Вычисление позиции и размеров, Layout.
    После того как у браузера появилось дерево рендеринга (Render Tree), он начинает «расставлять» элементы на странице. Этот процесс называется Layout.
    Чтобы понимать, где какой элемент должен находиться и как он влияет на расположение других элементов, браузер рассчитывает размеры и положение каждого рекурсивно(т.е. от самого верха спускаясь к дочерним).
    Расчёт начинается от корневого элемента дерева рендеринга, его размеры равны размеру вьюпорта. Далее браузер переходит поочерёдно к каждому из дочерних элементов.
    Если элементы не влияют на расположение и размеры других элементов, то их положение и размеры можно просчитать за один подход.
    Именно поэтому при вёрстке макетов рекомендуется «находиться в потоке» — чтобы браузеру не приходилось несколько раз пересчитывать один и тот же элемент, так страница отрисовывается быстрее.
    Глобальный Layout — это процесс просчёта всего дерева полностью, то есть каждого элемента.
    Инкрементальный — просчитывает только часть.
    Глобальный Layout запускается, например, при изменении размера окна, потому что браузеру требуется подогнать всю страницу под новый размер экрана. Это очень дорогой процесс.
    Инкрементальный Layout запускает пересчёт только «грязных» элементов. Это те элементы, которые были изменены, и их дочерние элементы, которые потянулись за родителями, потому что их положение и размеры могут зависеть от родителя.
  4. Непосредственно отрисовка, Paint
    Во время отрисовки (Paint) браузер наполняет пиксели на экране нужными цветами в зависимости от того, что в конкретном месте должно быть нарисовано: текст, изображение, цвет фона, тени, рамки и т. д.
    Отрисовка тоже бывает глобальной и инкрементальной. Чтобы понять, какую часть вьюпорта надо перерисовать, браузер делит весь вьюпорт на прямоугольные участки.
    Логика тут та же, как и в Layout — если изменения ограничены одним участком, то пометится «грязным» и перерисуется лишь он.
    Отрисовка — это самый дорогой процесс из всех, что мы уже перечислили.
    В общих чертах, отрисовка начинается с заднего плана и постепенно переходит к переднему:
    background-color;
    background-image;
    border;
    children;
    outline.

И Layout, и Paint работают за счёт CPU (central process unit), поэтому относительно медленные. Плавные анимации при таком раскладе невероятно дорогие.
Для плавных анимаций в браузерах предусмотрен композитинг (Compositing) - это разделение содержимого страницы на «слои», которые браузер будет перерисовывать.
Эти слои друг от друга не зависят, из-за чего изменение элемента в одном слое не затрагивает элементы из других слоёв, и перерисовывать их становится не нужно.
Именно из-за разнесения элементов по разным композиционным слоям свойство transform не так сильно нагружает браузер. Поэтому чтобы анимации не тормозили, их рекомендуется делать с применением transform и opacity.
Т.е. используя трансформ на хедере и трансформ aside, каждый трансформ вынесется на отдельный слой, который не будет затрагивать другие элементы, тем самым не будет ненужной перерисовки.

Ререндер.
5. Перерисовка, Reflow (relayout) и Repaint
Браузер перерисовывает экран каждый раз, когда на странице происходят какие-то изменения.
Если, например, в DOM-дереве добавился новый узел, или изменился текст, то браузер построит новое дерево рендеринга и запустит вычисление позиции и отрисовку заново.
Один цикл обновления — это animation frame.
Зная «расписание отрисовки» браузера, мы можем «предупредить» его, что хотим запустить какую-то анимацию на каждый новый фрейм. Это можно сделать с помощью requestAnimationFrame().
Это просто функция:
const animate = () => {
// Код анимации
}
Эта функция запускает новый кадр анимации: обновляет какое-то свойство или перерисовывает canvas.
Если мы хотим добиться плавной анимации, используя функцию выше, мы должны обеспечить в среднем 60 обновлений экрана за секунду (60 fps — frames per second).
Это можно было бы сделать топорно, через интервал:
// 60 раз в 1000 миллисекунд, приблизительно 16 мс.
const intervalMS = 1000 / 60
setInterval(animate, intervalMS)
НО!!! Интервалы не всегда запускаются в нужный момент. setInterval() не учитывает, на какой стадии отрисовки находится страница, и в итоге кадры отрисовки могут быть рваными или дёрганными.
С интервалом анимация может быть рваной, потому что перерисовка может быть запущена в неподходящее время.
А если вкладка была неактивна, то интервал может «попытаться догнать время», и несколько кадров запустятся разом.
С requestAnimationFrame() анимация плавнее, потому что браузер знает, что в следующем фрейме надо запустить новый кадр анимации.
Она не гарантирует, что анимация будет запущена строго раз в 16 мс, но значение будет достаточно близким.
window.requestAnimationFrame(animate)

Вывод:
Для динамики всегда используйте transform и opacity, избегайте изменения остальных свойств (типа left, top, margin, background и так далее).
Таким образом вы дадите браузеру возможность оптимизировать отрисовку, отчего страница станет отзывчивее.

Для анимаций, которые необходимо перерисовывать на каждый фрейм, используйте requestAnimationFrame().
Это сделает тяжёлую анимацию менее рваной.

115
Q

Что такое портал createPortal(Portal)?

A

Портал — компонент, который рендерит свое содержимое в другую часть DOM.
Порталы позволяют рендерить дочерние элементы в DOM-узел, который находится вне DOM-иерархии родительского компонента.
Портал создаётся с помощью ReactDOM.createPortal(child, container). Здесь child — это элемент, фрагмент или строка React, а container — это местоположение или узел DOM, в который должен добавляться портал.

Компонент, созданный через портал, мы наделяем ссылкой, рефом(это тот самый container), с которым будет связана, например, дивка.
Пример:
function App() {
const ref = useRef(null);
const [isRefReady, setIsRefReady] = useState(false);
useEffect(() => {
setIsRefReady(Boolean(ref));
}, []);

return (
<div>
<div>
{/* используя ссылку реф, мы вставляем дочерние элементы порталов */}
<header ref={ref} style={{display: “flex”, gap: 8 }} />
<hr/>
</div>
<h1>
Debug
</h1>
{isRefReady && createPortal(<button>one</button>, ref.current)}
{isRefReady && createPortal(<button>two</button>, ref.current)}
<div>
{isRefReady && createPortal(<button>three</button>, ref.current)}
</div>
</div>
);
}
Теперь в хедере у нас будут 3 кнопки.
Т.е. Он даже позволяет отображать несколько дочерних элементов из нескольких порталов в один и тот же целевой элемент.

Если даже написаны в компоненте порталы с наполнением, они будут отображаться только там, где написано об этом в container!!! а не в этой компоненте!!! Т.е. если у нас написан document.body, то в ДОМ мы увидим эти дочерние компоненты в корневом элементе!!

Вероятно, наиболее распространенным вариантом использования портала React.js является реализация модального компонента. Вы можете просто определить цель в корне дерева(document.body) вашего приложения и использовать компонент Portal для монтирования модального окна отовсюду, надежно плавающего над всем содержимым.

116
Q

Что такое прогрессивный рендеринг (progressive rendering)?

A

Чтобы понять что такое progressive rendering, нужно понимать отличие client-side rendering от server-side rendering.

При client-side rendering (CSR) контент отрисовывается на стороне клиента (в браузере). Такой подход используется в React, когда браузеру отсылается практически пустой HTML-документ, а потом запускается скрипт, который генерирует HTML в указанном скрипту теге. Как правило это <div id="root">. Пользователь будет видеть пустую страницу, пока JS-файл полностью не загрузится.

При server-side rendering (SSR) HTML-разметка генерируется на сервере, отсылается браузеру и после этого отрисовывается на клиенте. Пользователь увидит контент сразу же, но не сможет взаимодействовать со страницей, пока не загрузится JS-файл.

При использовании прогрессивного рендеринга, кусочки HTML генерируется на сервере и отсылаются браузеру в порядке их приоритетности. То есть, элементы с самым высоким приоритетом (например <header>, фон, главная интерактивная часть страницы) генерируются на сервере, отсылаются браузеру и отрисовываются в первую очередь. Это позволяет пользователю увидеть самый важный контент как можно скорее, не дожидаясь полной загрузки всего контента. То есть, progressive rendering что-то среднее между client-side rendering и server-side rendering.

Техники реализации прогрессивного рендеринга:

Ленивая загрузка (Lazy Loading). Загрузка контента по мере необходимости. Например, если страница достаточно большая, не нужно загружать изображения вне вьюпорта. Загрузка изображения стартует за некоторое время до того как она появится во вьюпорте. Эту же технику можно использовать для загрузки контента изначально скрытых элементов. Например, можно загрузить контент закрытого меню когда пользователь наводит курсор на кнопку открытия.
Приоритизация контента. Например, не загружать изначально все CSS-стили. Добавлять в <head> загрузку только тех стилей, которые нужны для текущей видимой области HTML-документа. Остальные стили можно добавить в <body>.

117
Q

Протоколы HTTP и HTTPS оба используются для передачи данных по сети, но есть важные различия между ними:

A

Безопасность:

HTTP (HyperText Transfer Protocol):
Это незащищенный протокол, который передает данные в открытом виде. Это означает, что любой, кто может перехватить передаваемые данные, может прочитать их без каких-либо дополнительных мер безопасности.
HTTPS (HyperText Transfer Protocol Secure):
Это защищенная версия HTTP. Вся передаваемая информация шифруется, что делает ее значительно более безопасной. Основное различие заключается в использовании протокола TLS (или его предшественника, SSL) для обеспечения шифрования данных.
Шифрование данных:

HTTP: Данные передаются в открытом виде, что делает их уязвимыми к перехвату и просмотру.
HTTPS: Данные шифруются, что означает, что даже если кто-то перехватывает их в процессе передачи, они не могут быть легко прочитаны без ключа шифрования.
Порты:

HTTP: Использует порт 80.
HTTPS: Использует порт 443.
Доверие и аутентификация:

HTTPS: Сайты, использующие протокол HTTPS, могут получить SSL-сертификат, который подтверждает их подлинность. Это помогает пользователям убедиться, что они связываются с настоящим сайтом и предотвращает атаки типа “Man-in-the-Middle” (человек посередине), где злоумышленник пытается подменить или перехватить коммуникацию между пользователем и сервером.

Пример атаки, который часто предотвращается HTTPS, - это атака “перехвата посредством прослушивания” (sniffing attack), при которой злоумышленник пытается перехватить и анализировать передаваемые данные. Использование шифрованного соединения HTTPS делает это значительно сложнее.

118
Q

SSR

A

Server-Side Rendering
При рендеринге на стороне клиента (CSR) получается простой HTML-документ с информацией о стилях CSS и файлом JavaScript, который будет отображать остальную часть сайта с помощью браузера. Это радикально отличается от использования SSR: сервер отвечает только за загрузку HTML и CSS, всё остальное обрабатывается библиотекой JavaScript на стороне клиента.

В случае наличия нового контента на уже загруженной странице CSR работает быстрее SSR, так как загружается только часть страницы с новым контентом, а не страница целиком.

У CSR есть минусы. Например, поскольку контент не отображается до тех пор, пока страница не будет загружена в браузер, SEO для веб-сайта пострадает.

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

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