May 22, 2022

Пытаемся в JS

Самое важное в JS:

  • Выражения
  • Функции
  • Объекты

Практически все сущности в JS — это объекты

Объект — набор свойств "имя:значение"

  • Массив — это объект
  • Функция — это объект
  • Число — это объект*
  • Строка — это объект*
    *Ведут себя как объекты

Console.log

console — это объект, в объектах есть свойства, и каждое свойство — это пара "ключ:значение".
log — это метод, метод — это функция, которая является значением одного из свойств объекта
С помощью точечной записи можно получать доступ к свойствам объекта

console.dir() — отображает все свойства объекта
console.table() — отображает все свойства объекта в табличном виде

Любое выражение всегда возвращает значение

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


Переменные

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

Имена переменных
PascalCase - типы и классы
DB_PASSWORD - значения известны до запуска приложения и не меняются
camelCase - все остальные переменные (используется чаще всего)

Объявление переменных

let - можно менять значения, по дефолту присваивается 'underfined'
const - нельзя менять значения (применять везде где это возможно)

Тип переменных определяется типом присвоенного значения

Отличие let, const и var

1) Переменные, которые мы объявляем через var можно обновлять и объявлять заново

2) Если переменная объявлена через var и она находится внутри функции, то область видимости этой переменной будет заканчиваться на этой функции соответственно и только

Область видимости var — это функция
Область видимости let и const — это блок

let и const можно объявлять лишь единожды


Примитивные типы

string (строка)
boolean (логический)
number (число)
null
underfined
symbol (символ)
Ссылочный тип
Если присвоить переменной значение объект, то переменная будет содержать в себе ссылку на этот объект, не его самого

Ссылочный тип

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

Динамическая типизация

const - выбор №1 в выборе типа переменной, чтобы не допустить возможных проблем в коде из-за динамической типизации (JS - это динамически типизируемый язык)

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

1. Все переменные объявлять перед их использованием
2. Стараться использовать const везде, где это возможно

Объекты

Объекты обладают свойствами
Если свойство содержит функцию как значение, то такое свойство называется метод
Практически все сущности в JavaScript - объекты
Объект - это набор свойств "имя:значение"
Объект - тип значений
Объект - тип переменных

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

Получение значений свойств

const myCity = {
city: 'New York',
popular: true,
country: 'USA'
}

Точечная запись/dot notation

Доступ к значению свойств через точку: console.log(myCity.city) // 'New York'
console.log(myCity.popular) // true

Изменение свойств объекта через точку: myCity.city = 'Los Angeles'
console.log(myCity.city) // 'Los Angeles'

Добавление новых свойств объекта через точку: myCity.language = 'English'
console.log(myCity.language) // 'English'

Удаление свойств объекта через точку: delete myCity.language = 'English'
console.log(myCity) // {city: 'Los Angeles', popular: true, country: 'USA'} (свойства 'language' больше НЕТ)

Вложенные свойства

const myCity = {
city: 'New York',
info: {
popular: true,
country: 'USA'
}
}

console.log(myCity.info.popular) // true

Удаление вложенного свойства

  1. delete myCity.info.popular
  2. delete myCity.info['popular']

Доступ к значению свойств через скобки:

Доступ к значению свойства с использованием скобок необходимо в том случае, если название свойства является значением той или иной переменной
myCity.info['popular'] = false

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

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

сonst name = 'Tim'
const postsQty = 23

const userProfile = {
name: name,
postsQty: postsQty,
hasSignedAgreement: false
}

Cокращенный формат записи:

const userProfile = {
name,
postsQty,
hasSignedAgreement: false
}

Сокращенные свойства рекомендуется располагать в начале объекта

Глобальные объекты

window – веб-браузеры
global – node.js
globalThis – унифицированный глобальный объект

К свойствам глобальных объектов можно обращаться без приписки "window" или "global": интерпретатор поймет, что происходит попытка обращения к свойству глобального объекта

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

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

const myCity = {
city: 'New York',
greetings: function () {
console.log('Greetings!!')
}
}

myCity.greentings() // 'Greetings!!'

myCity.greentings() — вызов метода
myCity.city — доступ к значению свойства

JSON

Конвертация JSON в объект:
JSON.parse()

Конвертация объекта в JSON:
JSON.stringify()

Мутирование объектов

Объект — ссылочный тип, переменная хранит ссылку на объект => можно менять значение тех или иных свойств — это и называется мутация объекта, на который ссылается переменная

Мутация копий возможность мутирования объекта, используя копию переменной, к которой ссылается объект

Как избежать мутаций

Вариант 1

const person = {
name: 'Bob',
age: 25
}

const person2 = Object.assign({}, person)

person2.age = 26

console.log(person.age) // 25
console.log(person2.age) // 26

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

Вариант 2

const person = {
name: 'Bob',
age: 25
}

const person2 = {...person}

person2.name = 'Alice'

console.name(person.name) // 'Bob'
console.name(person2.name) // 'Alice'

Ссылки на вложенные объекты сохраняются, также, как и в варианте 1

Вариант 3

const person = {
name: 'Bob',
age: 25
}

const person2 = JSON.parse(JSON.stringify(person))

person2.name = 'Alice'

console.name(person.name) // 'Bob'
console.name(person2.name) // 'Alice'

Ссылки на вложенные объекты в этом варианте НЕ СОХРАНЯЮТСЯ

Функции

Функция - блок кода, который можно выполнять многократно.

Функция может быть:
Именованной;
Присвоена переменной;
Анонимной;
Аргументом при вызове другой функции;
Значением свойства (метода) объекта

Функция - это объект
Функция возвращает underfined, если в ней нет инструкции return

Вызов функции

function myFn(a,b) { a += 1 const c = a + b return c }

myFn(3, 6) // 10

Передача значений по ссылке

const personOne = {
age: 21,
name: 'Bob'
}

function uncreasePersonAge (person) {
person.age += 1
return person
}

uncreasePersonAge(personOne)
console.log(personOne.age) // 22

Внутри функции выше мы мутируем внешний объект, что делать НЕ рекомендуется

Создание копии объекта

const personOne = {
name: 'Bob',
age: 21
}

function uncreasePersonAge(person) {
const updatedPerson = Object.assign({}, person)
updatedPerson.age += 1
return updatedPerson
}

const updatedPersonOne = uncreasePersonAge(personOne)
console.log(personOne.age) // 21
console.log(updatedPersonOne.age) // 22

Колбэк функции

Колбэк функции - функции, которые вызывают внутри себя другие функции

function anotherFunction() = {
// Действия...
}

function callBackAnotherFn(callBackFunction){
callBackFunction()
}

callBackAnotherFn(anotherFunction)

Правила работы с функциями

1. Называть функции исходя из выполняемых задач
2. Одна функция должна выполнять одну задачу
3. Не рекомендуется изменять внешние относительно функции переменные

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

Область видимости определяет границы действия переменной
Есть глобальные переменные (объявленные в глобальной области видимости) и локальные переменные (объявленные в локальной области видимости)

Правила работы с переменными
1. Все переменные объявлять перед их использованием
2. Стараться использовать const везде, где это возможно
3. Внутри функций не изменять переменные с внешних областей видимости

Операторы

Символьные:

1. Арифметические:
"+" — сложить
"-" — отнять
"/" — поделить
"*" — умножить

2. Сравнения: "===" — равно
"!==" — не равно
"<=" — меньше либо равно
">=" — больше либо равно

3. Логические: "!" — не
"&&" — и
"||" — или

4. Присваивания:
"=" — присвоить

Текстовые:

1. typeof — с помощью него можно проверить тип того или иного значения 2. instanceof — с помощью него можно проверить принадлежность объекта к тому или иному классу 3. new — 4. delete —

Операторы короткого замыкания

Оператор &&

Выражение 1 && Выражение 2

Если "Выражение 1" ложно:
1. Выражение 2 игнорируется
2. Возвращается результат "Выражения 1"

Мы ищем первое ложное значение

Если "Выражение 1" истинно, а "Выражение 2" ложно, возвращается результат "Выражения 2", также, как и если бы "Выражение 2" было бы истинно

Оператор ||

Выражение 1 || Выражение 2

Если "Выражение 1" истинно:
1. Выражение 2 игнорируется
2. Возвращается результат "Выражения 1"

Мы ищем первое истинное значение

Если "Выражение 1" ложно, а "Выражение 2" истинно, возвращается результат "Выражения 2", также, как и если бы "Выражение 2" было бы ложно

Трюк с оператором & и вызовом функции

const b = 1

b && console.log('Done!')
Это то же что и конструкция if, но в одну строчку кода

Оператор разделения объекта на свойства "..."

const button = {
width: 200,
text: 'Buy'
}

const redButton = {
...button,
color: 'red'
}

console.table(redButton)

В случае присутствия в объекте 'button' свойства 'color', значение этого свойства будет перезаписано на 'red'

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

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

Оператор "+" для объединения строк:

'Hello' + ' world!'

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

const hello = 'Hello'
const world = 'world!'

const greeting = hello + ' ' + world

Шаблонные строки

const hello = 'Hello'
const world = 'world!'

const greeting = ${hello} ${world}

В примере выше может быть любое выражение, например, вызов функции

Функциональные выражения

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

Функциональное выражение в вызове другой функции

setTimeout(function() {
console.log('Отложенное сообщение')
}, 1000)

// 'Отложенное сообщение' будет выведено в консоль через 1000 мс (1 сек)

Стрелочные функции

Пример стрелочной функции

(a, b) => {
let c
a = a + 1
c = a + b
return c
}

Стрелочная функция - это выражение, стрелочная функция всегда анонимная

Как дать имя стрелочной функции?

const myFunction = (a, b) => {
let c
a = a + 1
c = a + b
return c
}

myFunction(5, 3) // 9

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

Если объявлять переменную используя "const", будет невозможно присвоения нового значения для этой переменной, благодаря этому можно предотвратить случайное изменение значения такой переменной

Если объявлять функцию традиционно через function и сразу же давать ей имя, возможно присвоение нового значения для этой переменной

Использование стрелочной функции в качестве колбэк-функции (использование стрелочной функции в вызове другой функции)

setTimeout(() => {
console.log('Отложенное сообщение')
}, 1000)

// 'Отложенное сообщение' будет выведено через 1000 мс (1 сек)

Сокращение стрелочных функций

Если один параметр, то круглые скобки можно опустить:

a => {
//тело функции
}

Так делать нежелательно, поскольку читабельность кода становится в разы сложнее

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

(a, b) => a + b

В этом случае функция неявно возвращает результат выражения

Значения параметров функции по умолчанию

Пример 1

function multByFactor(value, multiplier = 1) {
return value * multiplier
}

multByFactor(5, 10) // 50
multByFactor (5) // 5

Пример 2

const myNewPost = (person, date = Date()) => ({
...person,
addedDate, // (сокращенный формат записи свойства объекта)
}) (оборачиваем в скобки, чтобы функция вернула новый объект неявно)

const firstPost = {
id: 123,
author: 'Tim'
}

myNewPost(firstPost)

Обработка ошибок

Что происходит в случае ошибок

try/catch

Пример

const fnWithError = () => {
throw new Error('Some error');
}
try {
fnWithError();
} catch (error) {
console.error(error);
console.log(error.message);
}
console.log('Continue...');

В данном случае наша ошибка обойдет проблемы uncaught error (не пойманная ошибка) и мы с ней сможем поработать.

Инструкции

Выражение всегда возвращает значение.

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

Как отличить выражение от инструкции

Выражение может быть использовано в качестве аргумента при вызове функций

Массивы

Массив — это объект с цифровыми именами свойств

Формат записи массивов

const myArray = [1, 2, 3]
console.log(myArray) // [1, 2, 3]

constmyArray2 = new Array(1, 2, 3)
console.log(myArray) // [1, 2, 3]

Структура массива

Абсолютно индентичные массивы с одиннаковым и равным количеством элементов не равны между собой, так как они ссылаются на разные объекты в памяти

Массив vs объект

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

Чтение значений массива

const myArray = [1, true, 'a']
console.log(myArray) = // [1, true, 'a']

console.log(myArray[0]) // 1
console.log(myArray[1]) // true

console.log(myArray.length) // 3

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

Изменение и добавление элементов массива

const myArray = [1, 2, 3, 4]
console.log(myArray.length) // 4

myArray[2] = 'abc'

console.log(myArray) // [1, 2, 'abc, 4]
console.log(myArray.length) // 4

myArray[4] = true

console.log(myArray) // [1, 2, 'abc', 4, true]

console.log(myArray.length) // 5

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

Функции высшего порядка в массивах/функции прототипов/методы прототипов push
pop
shift
unshift
Each
map

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

LENGTH

Позволяет нам узнать длину массива

const myArr = [
true,
1,
'Tim,
]

console.log(myArr.length) // 3

Также с помощью метода length можно укорачивать исходный массив

const myArr = [
true,
1,
'Tim,
]

myArr.length = 2
console.log(myArr) // (2), [true, 1]

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

1) Очередь/ упорядоченная коллекция элементов

Очередь поддерживает 2 вида операций

  1. Добавление элементов в конец очереди
  2. Удаление элементов в начале, сдвигая очередь так, что второй элемент становится первым

2) Структура данных Стек

Стек поддерживает 2 вида операций

  1. Добавление элементов в конец
  2. Удаление последнего элемента

Массивы в JS могут работать и как очереди, и как стек

PUSH

Добавляет новый элемент/несколько элементов в конец массива

const myArray = [1, 2, 3, 4]

myArray.push(true)

console.log(myArray) // [1, 2, 3, 4, true]

myArray.push(false, 'Tim')

console.log(myArray) // [1, 2, 3, 4, true, false, 'Tim']

POP

Удаляет последний элемент массива и возвращает его

const myArray = [1, 2, 3, 4]

myArray.pop()

console.log(myArray) // [1, 2, 3]

const removedElement = myArray.pop()

console.log(myArray) // [1, 2]
console.log(removedElement) // 3

UNSHIFT

Добавляет элемент в начало массива (редко используется)

const myArray = [1, 2, 3, 4]

myArray.unshift(true)

console.log(myArray) // [true, 1, 2, 3, 4]

SHIFT

Удаляет первый элемент массива сдвигая все оставшиеся элементы массива влево (первый стал нулевым, второй первым и тп) и возвращает его

const myArray = [true, 1, 2, 3, 4]

const removedElem = myArray.shift()

console.log(myArray) // [1, 2, 3, 4]

Метод splice

1) Удаляет конкретный элемент массива и возвращает его

myArray.splice(a, b, c, ..., n), где
a — стартовая позиция (ключ)
b — количество элементов, которые мы хотим удалить

c, ..., n — элементы, которые мы хотим добавить

const myArray = [true, 1, 2, 3, 4]

const removerElem = myArray.splice(3, 1)

console.log(removedElem) // 3
console.log(myArray) // [true, 1, 2, 4]

2) Заменяет конкретный элемент массива

const myArray = [true, 1, 2, 3, 4]

myArray.splice(0, 1, false)

console.log(myArray) // [false, 1, 2, 3, 4]

3) Добавляет элементы в массив

const myArray = [true, 1, 2]

myArray.splice(1, 0, 'Tim', 'Jake')

console.log(myArray) // [true, 'Tim', 'Jake', 1, 2]

4)  Удаляет элемент массива с конца

const myArray = [true, 1, 2]

myArray.splice(-1, 1)

console.log(myArray) // [true, 1]

Метод slice

someArr.slice([start], [end])

Возвращает новый массив, в который копирует все элементы, начиная со start до end не включительно. Оба индекса start и end могут быть отрицательными. В таком случае отсчёт будет осуществляться с конца массива.

const myArr = [1, 2, 3, 4]

const newArr = myArr.slice([1], [2])

const newArr2 = myArr.slice([-2],[-1])

const newArr3 = myArr.slice([-1])

console.log(newArr) // [2] console.log(newArr2) // [3] console.log(newArr3) // [4]

Можно вызвать slice и вообще без аргументов: myArr.slice() создаёт копию массива myArr. Это часто используют, чтобы создать копию массива для дальнейших преобразований, которые не должны менять исходный массив.

Метод concat

Метод arr.concat создаёт новый массив, в который копирует данные из других массивов и дополнительные значения:

arr.concat(arg1, arg2...)

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

В результате мы получаем новый массив, включающий в себя элементы из arr, а также arg1, arg2и так далее…

Если аргумент argN – массив, то все его элементы копируются. Иначе скопируется сам аргумент.

const myArr = [1, 2, 3, 4]

const newArr = myArr.slice([1], [2]) // 2

const newArr2 = myArr.slice([-1]) // 4

let includeArr = myArr.concat(newArr, newArr2) // [1, 2, 3, 4, 2, 4]

console.log(includeArr)

Поиск в массиве

indexOf/lastIndexOf и includes

  • arr.indexOf(item, from) ищет item, начиная с индекса from, и возвращает индекс, на котором был найден искомый элемент, в противном случае -1.
  • arr.lastIndexOf(item, from) – то же самое, но ищет справа налево.
  • arr.includes(item, from) – ищет item, начиная с индекса from, и возвращает true, если поиск успешен.

const myArr = ['Tim', 'Den', 'Jake', 'Mike']

console.log(myArr.indexOf('Mike')) // 3
console.log(myArr.lastIndexOf('Mike')) // 3
console.log(myArr.includes('Mike')) // true
console.log(myArr.indexOf('Mike', 2)) // 3
console.log(myArr.lastIndexOf('Den', 2)) // 1
console.log(myArr.includes('Den', 2)) // false

Find и findIndex

Синтаксис метода find()

let result = arr.find(function(item, index, array) { // если true - возвращается текущий элемент и перебор прерывается // если все итерации оказались ложными, возвращается undefined });

Метод arr.findIndex – по сути, то же самое, но возвращает индекс, на котором был найден элемент, а не сам элемент, и -1, если ничего не найдено.

const myArrWithObj = [  
   {name: 'Tim', age: 21},  
   {name: 'Jake', age: 25},  
   {name: 'Juan', age: 23},
];

const returnCorrectAge = myArrWithObj.find(item => item.age === 21);
console.log(returnCorrectAge); // { name: 'Tim', age: 21 }

const returnCorrectIndex = myArrWithObj.findIndex(item => item.age === 23);
console.log(returnCorrectIndex); // 2

Метод Filter

Метод find ищет один (первый попавшийся) элемент, на котором функция-колбэк вернёт true.

На тот случай, если найденных элементов может быть много, предусмотрен метод arr.filter(fn).

Синтаксис этого метода схож с find, но filter возвращает массив из всех подходящих элементов:

let results = arr.filter(function(item, index, array) {
  // если true - элемент добавляется к результату, и перебор продолжается
  // возвращается пустой массив в случае, если ничего не найдено
});

const myArrWithObj = [  
{name: 'Tim', age: 21},  
{name: 'Jake', age: 25},  
{name: 'Juan', age: 23},];

const returnCorrectAge = myArrWithObj.filter(item => item.age > 21);

console.log(returnCorrectAge); // [ { name: 'Jake', age: 25 }, { name: 'Juan', age: 23 } ]

console.log(returnCorrectAge.length); // 2

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

Метод Sort()

Элементы по умолчанию сортируются как строки.

Сортировка массива по возрастанию

const myArr = [4, 13, 3, 763, 94];
const myArr1 = myArr.sort((a, b) => { return a - b });

Метод reverse()

Метод arr.reverse меняет порядок элементов в arr на обратный.

let arr = [1, 2, 3, 4, 5];
arr.reverse();

alert( arr ); // 5,4,3,2,1

Он также возвращает массив arr с изменённым порядком элементов.

Метод map

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

Вызывает функцию для каждого элемента массива и возвращает новый массив с результатами выполнений этой функции

Функция, возвращающая первые символы элементов массива

const myArr = ['Tim', 'Dan', 'Jake'];

const myArr1 = myArr.map((item, index, arr) => { return item[0] });

item - каждый элемент массива
index - ключ/позиция каждого элемента массива
arr - массив, с которым работаем

Split и join

Split - преобразовывает строку в массив по заданному разделителю.

Синтаксис: arr.split(delim)

Преобразование строки в массив:

const stringVal = 'Boba,Buba,Biba'
const myArr = stringVal.split(',')
console.log(myArr);

Join - преобразовывает массив в строку с заданным разделителем.

Синтаксис: arr.join(glue)

Преобразование массива в строку:

const arrVal = ['Boba', 'Buba', 'Biba']
const myArr = arrVal.join(', ')
console.log(myArr);

Метод isArray

Проверка массива на принадлежность к типу данных "массив":

const arr = []const obj = {}
const typeCheck = (val) => {  
    if (Array.isArray(val)) {    
        console.log('Это массив')  
    } else {    
        console.log('Это не массив')  
    }
}
typeCheck(arr)typeCheck(arr) // 'Это массив'
typeCheck(obj)typeCheck(obj) // 'Это не массив'

Перебор массива

Метод forEach

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

forEach - выполняет функцию для каждого элемента массива.

const myArr = ['Биба', 'Боба', 'Бэбрик'];
myArr.forEach((item, index, array) => {   
    console.log(`${item} находится на ${index} позиции в ${array}`) 
});

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

Reduce и reduceRight

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

Синтаксис:

let value = arr.reduce(function(previousValue, item, index, array) {
  // ...
}, [initial]);

Функция применяется по очереди ко всем элементам массива и «переносит» свой результат на следующий вызов.

Аргументы:

  • previousValue – результат предыдущего вызова этой функции, равен initial при первом вызове (если передан initial),
  • item – очередной элемент массива,
  • index – его индекс,
  • array – сам массив.

Пример применения reduce:

const myArr = [1, 2 , 3, 4]
const res = myArr.reduce((previousValue, item, index, array) => {  
        return previousValue + item;
    }, 0)
console.log(res) // 10

Если начальное значение (previousValue) не указано, по умолчанию оно становится равным первому элементу массива.

Метод reduceRight работает аналогично с методом reduce, но проходит массив справа налево

Деструктуризация

Деструктуризация объектов

Как присвоить некоторые значения свойств объекта переменным:

Пример:

const myObj = {
    nameOf: 'Tim',
    age: 21,
    sex: 'Male',
    learnJs: true,
}
const {nameOf, sex} = myObj /* в ф. скобках можно указать одно, все: 
любые свойства объекта */
console.log(nameOf) // 'Tim'
console.log(sex) // 'Male'

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

Деструктуризация массивов

Пример:

const myArr = ['Orange', 'Coconut']
const [myArrOne, myArrTwo] = myArr
/* Важно понимать, что в отличие от объектов, порядок элементов 
массива важен. Поэтому необходимо учитывать этот факт 
при деструктуризации массивов*/
console.log(myArrOne) // 'Orange'
console.log(myArrTwo) // 'Coconut'

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

Пример:

const myObj = {
    nameOf: 'Tim',
    comments: 23,
    work: true,
    sex: 'Male'
}
const objObj = {
    nameOf: 'Jack',
    work: false,
    sex: 'Male'
}
const howManyComments = ({comments, work, nameOf}) => { // здесь нет необходимость указывать let или const в блоке параметров потому что мы знаем, что параметры это и есть переменные, значения которых меняются при вызове функции
    if (!work) {
        return `User ${nameOf} hasn't comments`
}
    return `User ${nameOf} has ${comments} comments`
}
console.log(howManyComments(myObj)) // User Tim has 23 comments
console.log(howManyComments(objObj)) // User Jack hasn't comments

В данном примере в блоке аргументов объявления функции мы можем выполнить деструктуризацию элементов входного объекта при вызове функции. Мы хотим взять свойства с именами nameof, work, comments из значения которое будет передано в вызове функции (объект), создать новые переменные с названиями nameof, work, comments и присвоить им соответсвующее значение.

Условные инструкции

Инструкция if

if (условие) {
// Блок кода, выполняемый однократно, если Условие правдиво
}

Популярное использование условной конструкции if

const person = {
age: 20
}

if (!person.name) {
console.log("Имя не указано")
// Другие действия в случае, если свойства 'name' у объекта 'person' нет
}

Инструкция if else

if (условие) {
// Блок кода, выполняемый однократно, если Условие правдиво
} else {
// Блок кода, выполняемый однократно, если Условие ложно
}

Инструкция if else if

if (Условие 1) {
// Блок кода, выполняемый однократно, если Условие 1 правдиво
} else if (Условие 2) {
// Блок кода, выполняемый однократно, если Условие 2 правдиво
} else {
// Блок кода, выполняемый однократно, если предыдущие условия ложны
}

Использование if в функциях

Популярный подход использования if в функциях:

const sumPositiveNumbers = (a, b) => {
if ((typeof a !== 'number') || (typeof b !== 'number')) {
return 'Один из аргументов не число'
}

if ((a <= 0) || (b <= 0)) {
return 'Один из аргументов не положительное число'
}

return a + b

}

Инструкция switch

switch (Выражение) {
case A:
// Действия если Выражение === A
break
case B:
// Действия если Выражение === B
break
default:
// Действия по умолчанию
}

Тернарный оператор

Конструкция с тернарным оператором — выражение (выражение всегда возвращает значение)

Условие ? Выражение 1 : Выражение 2

Условие — любое выражение
Если условие правдиво, то возвращается результат Выражения 1
Если условие ложно, то возвращается результат Выражения 2

Второй, более предпочтительный способ:

Условие
? Выражение 1
: Выражение 2

Пример тернарного оператор

const val = 11

value
? console.log('Условие истинно')
: console.log('Условие ложно')

Вернет undefined

Циклы

Все циклы — это инструкции

Типы циклов

for
for..in..
while
do..while
for..of..

For

for (Начальная инструкция; Условие; Итерационное действие) {
// Блок кода, выполняемый на каждой итерации
}

Пример использования цикла for

for (let i = 0; i < 5; i++) {
console.log(i)
}

Для перебора массивов не нужен for

Цикл for для массивов

const myArray = ['first', 'second', 'third']

for (let i = 0; i < myArray.length; i++) {
console.log(myArray[i])
}

// 'first'
// 'second'
// 'third'

Для работы с массивами можно использовать циклы, но этого делать не рекомендуется. Лучше использовать функции высшего порядка для массивов ('forEach', 'map', 'reduce')

Метод для массивов forEach

const myArray = ['first', 'second', 'third']

myArray.forEach((element, index) => {
console.log(element, index)
})

While

while (Условие) {
// Блок кода, выполняемый на каждой итерации
}

let i = 0

while (i < 5) {
console.log(i)
i++
}

Do while

do {
// Блок кода, выполняемый на каждой итерации
} while (Условие)

Цикл do while необходимо использовать, если мы хотим повторить действие хотя бы раз

let i = 0

do {
console.log(i)
i++
} while (i < 5)

For in

for (key in Object) {
// Действия с каждым свойством объекта
// Действия свойства — Object[key]
}

const myObject = {
x: 10,
y: 15,
z: 20
}

for (const key in myObject) {
console.log(key, myObject[key])
}

// x 10
// y 15
// z 20

For in для объектов

Методы keys и values для объектов

Получение всех ключей объекта в виде массива

const myObject = {
x: 10,
y: true,
z: 'abc'
}

Object.keys(myObject).forEach(key => {
console.log(key, myObject[key])
})

Объекты возможно преобразовывать в массивы, используя методы keys и values

For in для массивов

const myArray = [true, 10, 'abc', null]

for (const key in myArray) {
console.log(myArray[key])
}

For of

for (Element of Iterable) {
// Действия с определенным элементом
}

Пример применения for of для строки

const myString = 'Hey'

for (const letter of myString) {
console.log(letter)
}

В результате в консоли мы получим:

Пример применения for of для массива

const myArray = [true, 10, 'abc', null]

for (const element of myArray) {
console.log(element)
}

В результате мы получим в консоли:

Желательно для массивов использовать их методы, а не циклы

For of НЕ подходит для объектов, так как объект это неитерируемый элемент в JS

Модули

Модули позволяют структурировать код, избегать дублирования блоков кода.

Import & export

Экспорт по умолчанию

Классы и прототипы

Синтаксис классов появился в ES6

class ...
  • Классы позволяют создавать прототипы для объектов
  • На основании прототипов создаются экземпляры
  • Экземпляры могут иметь свои собственные свойства и методы
  • Экземпляры наследуют свойства и методы прототипов

Название классов начинается с паскаль-кейса (с большой буквы)

Пример класса в JS:

class Comment {
    constructor(text){
        this.text = text;
        this.votesQty = 0;
    }
    upvote(){
        this.votesQty += 1;
    }
}

Создание экземпляров класса

Мы можем создать экземпляр класса с помощью ключевого слова new:

const firstComment = new Comment('First comment');

Собственные свойства экземпляра

Наследование по цепочке

В данном примере объект 'firstComment' имеет свои собственные свойства, наследует все методы класса Comment, а также наследует все методы класса Объект.

Цепочка прототипов

Проверка пренадлежности классу

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

Вызов унаследованных методов

Методы можно вызывать многократно

Проверка принадлежности свойств экземпляру объекта

Чтобы проверить, пренадлежит ли экземпляру свойство, мы можем воспользоваться методом hasOwnProperty:

Статические методы

Метод доступен как свойство класса и не наследуется экземплярами класса

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

Расширение других классов

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

Прототип

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

Промисы

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

Состояния промиса

  • Ожидание
  • Исполнен
  • Отклонен

Создание и использование промисов

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

Получение результата промиса

Для удобства чтения таких методов следует вызывать их на отдельных строках кода.

Вызов fetch внутри промиса

Метод .json() возвращает промис.

ASYNC/AWAIT

Async/await — специальный синтаксис для упрощения работы с промисами

Асинхронная функция

Асинхронная функция — это функция, которая возвращает промис

Асинхронная функция всегда возвращает промис.

Использование await внутри асинхронных функций

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

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

Ожидание результата await

Функция дальше не выполняется пока не получен результат промиса (исполнен/отклонен)

Переход с промисов на async/await

await можно использовать только внутри асинхронных функций

В примере выше нет обработки ошибок:

Ошибка не выявлена

Обработка ошибок в асинхронных функциях

try/catch

С помощью конструкции try/catch добавляем обработку ошибок

Ошибка высвечивается

Главное в async/await

  1. async/await — это синтаксическая надстройка над промисами
  2. await синтаксис возможен только внутри async функций
  3. async функция всегда возвращает Promise
  4. async функция ожидает результата инструкции await и не выполняет последующие функции


Всё что не видео-курс

__proto__ vs prototype

prototype- это объект.
__proto__ - это объект, который ссылается на какой-то прототип.

__proto__

__proto__ есть у всех объектов:

a = {}; // a.__proto__
b = []; // b.__proto__
c = 18; // c.__proto__
d = 'abc' // d.__proto__
function e(){} // e.__proto__
let f = function(){}; // f.__proto__
let g = () => {}; // g.__proto__
class h {} // h.__proto__
let i = true // i.__proto__

Что такое __proto__?

Почти всегда это объект.

Разные __proto__ разных по типу объектов - совершенно независимые разные объекты. У одинаковых по "типу" объектов - они равны, то есть это один и тот же объект.

Любой объект создается с помощью конструктора либо класса.

Чтобы понимать, что это за __proto__, нужно ТОЧНО знать с помощью какой функции-конструктора (класса) создан данный объект.

У любого объекта есть __proto__
У любого объекта, который одновременно с этим является классом либо функцией, объявленной через "function", есть prototype
У любого класса или функции, объявленной через function есть prototype

Каждый prototype - это независимый объект, сам по себе, с определенным набором свойств и методов.

Т.е. __proto__ есть у каждого объекта, а prototype есть либо у class либо у function.

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

Зачем классу нужен объект prorotype

Зачем объектам, созданным с помощью этого класса, нужно свойство __proto__, которое ссылается на этот объект prototype

Если мы пытаемся прочитать свойство объекта, либо вызвать его метод, а данного свойства/метода нет, то объект полезет искать его через ссылку __proto__ в prototype класса, с помощью которого он был создан.

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