Contents
- 1 Вводная часть по работе с Javascript
- 2 Функции в Javascript
- 3 Arrays / Массивы — Часть 1
- 4 Objects / Объекты Javascript & JSON
- 5 Classes / Классы
- 6 Loops and Template Strings / Циклы и строки шаблона
- 7 Web Requests, Callbacks and Promises / Веб-запросы, обратные вызовы и обещания
Вводная часть по работе с Javascript
Переменные в JavaScript
Объявить переменную в JS можно тремя разными способами
- var — самый распространенный способ объявления переменной. Такую переменную можно повторно объявить и обновить значение, но доступ к ней возможен только внутри функции и вложенных в неё функциях.
- const — Не могут быть переназначены. В JavaScript
const
означает, что идентификатор нельзя переназначить. - let — переменную нельзя повторно объявить, но можно обновить её значение. Область видимости ограничена блоком, т.е. во вложенных функция переменная будет недоступна.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function varTest() { var x = 1; if (true) { var x = 2; // та же переменная! console.log(x); // 2 } console.log(x); // 2 } function letTest() { let x = 1; if (true) { let x = 2; // другая переменная console.log(x); // 2 } console.log(x); // 1 } |
Если запустить код
1 2 |
let testVariable = 1; let testVariable = 2; |
то вы получите ошибку
1 |
Uncaught SyntaxError: Identifier 'testVariable' has already been declared |
Правильный код:
1 2 |
let testVariable = 1; testVariable = 2; |
Для чистоты кода лучше использовать let.
Операторы сравнения
==
— Равно===
— Равноценный и равный тип!=
— Не равный!==
— Не равное значение или не равный тип>
— Больше, чем<
— Меньше, чем>=
— Больше или равно<=
— Меньше или равно?
— Тернарный оператор
Пример использования оператора «?»:
1 |
let result = condition ? 'result true' : 'result false'; |
Логические операторы
&&
— Логическое и||
— Логическое или!
— Логическое не
Ввод/Вывод данных
Рассмотрим функции ввода и вывода данных:
alert()
— Вывод данных в окне предупреждения в окне браузераconfirm()
— Открывает диалог да / нет и возвращает истину / ложь в зависимости от щелчка пользователяconsole.log()
— Записывает информацию в консоль браузера, удобную для отладки.document.write()
— Пишет прямо в HTML-документprompt()
— Создает диалог для пользовательского ввода
Циклы
Оператор switch-case
Оператор switch-case
используется для того, чтобы выбрать один из множества блоков кода для выполнения.
Синтаксис
1 2 3 4 5 6 7 8 9 10 |
switch(expression) { case x: // code block break; case y: // code block break; default: // code block } |
Вот как это работает:
- Выражение переключения вычисляется один раз.
- Значение выражения сравнивается со значениями для каждого случая.
- Если есть совпадение, выполняется связанный блок кода.
- Если совпадений нет, выполняется блок кода по умолчанию.
Пример
Метод getDay()
возвращает день недели как число между 0 и 6.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
switch (new Date().getDay()) { case 0: day = "Sunday"; break; case 1: day = "Monday"; break; case 2: day = "Tuesday"; break; case 3: day = "Wednesday"; break; case 4: day = "Thursday"; break; case 5: day = "Friday"; break; case 6: day = "Saturday"; } |
Обработка ошибок в JavaScript — Throw, Try & Catch
При выполнении кода JavaScript могут возникать разные ошибки. При возникновении ошибки JavaScript обычно останавливается и генерирует сообщение об ошибке.
- Оператор
try
позволяет вам проверить блок кода на наличие ошибок. - Оператор
catch
позволяет вам обработать ошибку. - Оператор
throw
позволяет создавать собственные ошибки. - Оператор
finally
позволяет выполнить код, независимо от наличия или отсутствия ошибок при выполнении блока кода.
Синтаксис try catch:
1 2 3 4 5 6 |
try { Block of code to try } catch(err) { Block of code to handle errors } |
Синтаксис throw:
1 2 3 4 |
if(x == "") throw "empty"; if(isNaN(x)) throw "not a number"; if(x < 5) throw "too low"; if(x > 10) throw "too high"; |
Синтаксис try catch finally:
1 2 3 4 5 6 7 8 9 |
try { Block of code to try } catch(err) { Block of code to handle errors } finally { Block of code to be executed regardless of the try / catch result } |
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function myFunction() { var message, x; message = document.getElementById("p01"); message.innerHTML = ""; x = document.getElementById("demo").value; try { if(x == "") throw "is empty"; if(isNaN(x)) throw "is not a number"; x = Number(x); if(x > 10) throw "is too high"; if(x < 5) throw "is too low"; } catch(err) { message.innerHTML = "Error: " + err + "."; } finally { document.getElementById("demo").value = ""; } } |
Функции в Javascript
Обычные именованные функции
Функция — это подпрограмма, которая получает на вход данные, преобразует их и возвращает результат. Результат, возвращаемый функцией можно передать в переменную. Функция задается один раз и затем может вызываться необходимое количество раз.
Пример объявления функции sum с двумя параметрами:
1 2 3 4 5 6 7 8 9 10 |
function sum(a, b) { return a + b; } const num1 = 5; const num2 = 8; const res = sum(num1, num2); console.log(res); // 13 |
Функция может иметь несколько параметров или вообще не иметь параметров. В следующем примере bark не перечисляет никаких имен параметров, тогда как power перечисляет два:
Пример функции bark( )
1 2 3 4 |
function bark() { return "woof-woof"; } bark(); // woof-woof |
Пример функции power( )
1 2 3 4 5 6 7 8 |
function power(base, exponent) { let result = 1; for(let count = 0; count < exponent; count++) { result *= base; } return result; } power(2, 10); // 1024 |
Также функция может не возвращать значение, а совершать определенное действие, например выводить текст в консоль:
1 2 3 4 5 |
function sayHello(nameStr) { console.log('Hello, ' + nameStr); } sayHello('Ivan'); // Hello, Ivan |
Анонимная функция и Функциональные выражения
Функция анонимна, если у нее нет имени. Объявление функции в операторе всегда начинается с ключевого слова function
. В противном случае это функциональное выражение.
Можно записать функцию в переменную и затем вызвать ее через название этой переменной:
1 2 3 4 5 6 7 8 |
// Function expression: starts with "var" var fullName = function(firstName, lastName) { return `${firstName} ${lastName}`; } console.log(fullName("Sergei", "Mironov")); console.log(fullName); console.log(typeof(fullName)); |
Результат:
1 2 3 4 5 |
Sergei Mironov ƒ (firstName, lastName) { return `${firstName} ${lastName}`; } function |
Разумно отдавать предпочтение именованным функциям и избегать анонимных, чтобы получить такие преимущества, как:
- Сообщения об ошибках, стеки вызовов показывают более подробную информацию при использовании именованных функций;
- Более удобная отладка за счет уменьшения количества анонимных имен стека;
- Название функции говорит о том, что функция делает;
- Вы можете получить доступ к функции внутри ее области видимости для рекурсивных вызовов или отключения прослушивателей событий.
Стрелочные функции — Arrow function
Стрелочная функция — это сокращенная запись функциональных выражений с помощью синтаксиса =>
.
Стрелочная функция не создает свой контекст выполнения, но принимает его лексически (в отличие от выражения функции или объявления функции, которые создают собственный контекст в this
зависимости от вызова)
Стрелочная функция определяется с помощью пары круглых скобок, которые содержат список параметров (param1, param2, ..., paramN)
, за которыми следует толстая стрелка =>
и пара фигурных скобок {...}
, ограничивающих основной блок кода.
Неявный и явный возврат
У нас есть несколько способов написания наших стрелочных функций. Это потому, что стрелочные функции могут иметь ключевое слово «подразумеваемый возврат» или «явный возврат».
В обычных функциях, если вы хотите что-то вернуть, вам нужно использовать ключевое слово return
. В стрелочных функциях тоже есть return. Когда вы используете return
, это называется явным возвратом . Тем не менее, стрелка позволяет делать так называемый подразумеваемый возврат, когда return
ключевое слово можно пропустить. Давайте посмотрим на несколько примеров:
Пример 1: нормальное функциональное выражение
1 2 3 |
const sayHi = function(name) { return name; } |
Пример 2: стрелочная функция с явным возвратом
1 2 3 4 5 6 7 |
// Multi-line const sayHi = (name) => { return name; } // Single-line const sayHi = (name) => { return name } |
Пример 3: стрелочная функция с неявным возвратом
1 2 3 4 5 6 7 |
// Single-line const sayHi = (name) => name // Multi-line const sayHi = (name) => ( name ) |
Когда вы используете фигурные скобки {}
, вам нужно явно указать возврат. Однако, когда вы не используете фигурные скобки, return
подразумевается, и вам этого делать не нужно.
Когда вы используете фигурные скобки, как в примере 2 , это называется телом блока . А синтаксис в примере 3 называется кратким телом.
Скобки
В обычных функциях нам всегда необходимо использовать круглые скобки для параметров. Однако для стрелочных функций скобки необязательны, если имеется ТОЛЬКО один параметр.
Скобки необязательны для ОДНОГО параметра:
1 2 3 4 5 6 7 8 |
// Normal Function const numbers = function(one) {} // Arrow Function, with parentheses const numbers = (one) => {} // Arrow Function, without parentheses const numbers = one => {} |
Скобки обязательны для НЕСКОЛЬКИХ параметров:
1 2 3 4 5 |
// Normal Function const numbers = function(one, two) {} // Arrow Function, with parentheses const numbers = (one, two) => {} |
Стрелочные функции служат двум основным целям:
- более сжатый синтаксис
- и совместное использование лексики
this
с родительской областью видимости.
Generator Function — Функция генератора
Генератор — это функция, которая может остановиться на полпути, а затем продолжить с того места, где она остановилась. Генератор выглядит как функция, но ведет себя как итератор.
Генератор создает функциональный объект, в свою очередь создающий объект, содержащий метод next, сделанный из тела function*. В этом теле имеется оператор yield, напоминающий оператор return, но он не дает ожидаемого значения. Вместо этого он создает объект, в котором имеется свойство value, содержащее ожидаемое значение.
Примечание: async / await основан на генераторах.
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function * generatorFunction() { yield 'Hello, '; console.log('I will be printed after the pause'); yield 'World!'; } const generatorObject = generatorFunction(); console.log(generatorObject.next().value); console.log(generatorObject.next().value); console.log(generatorObject.next().value); // output should be following below. // Hello, // I will be printed after the pause // World! // undefined |
Подборка видео по функциям в JS
Arrays / Массивы — Часть 1
В этом разделе будут описаны основы работы с массивами, а также приведены примеры как добавлять, обновлять и удалять значения
Определение массива / array
В JavaScript Массив или Array — это структура данных, содержащая список элементов, которые хранят несколько значений в одной переменной. Массивы могут содержать элементы одного типа данных или смеси типов данных.
Сила массивов JavaScript заключается в свойствах и методах массива, которые помогут Вам решить любую задачу, связанную с массивами.
Методы массивов — это встроенные в JavaScript функции, которые мы можем применять к нашим массивам. Каждый метод имеет уникальную функцию, которая выполняет изменение или вычисление нашего массива и избавляет нас от написания общих функций с нуля.
Расположение элементов внутри массива приводит к особой структуре, из-за которой массивы называются особым типом структуры данных. Термин «структура данных» относится к расположению данных таким образом, что установка и извлечение элементов очень просты и следуют определенному шаблону.
По сути, массив может просто содержать простые элементы данных, такие как числа и строки, или, в более сложных сценариях, они могут содержать сложные объекты. В частности, в JavaScript массивы основаны на хэш-таблицах, и они не обязательно размещаются в непрерывных ячейках памяти.
Массивы JavaScript основаны на индексах, и мы можем устанавливать и извлекать элементы на основе их индексов. JavaScript по существу не поддерживает концепцию ассоциативных массивов, что означает, что он не извлекает и не устанавливает элементы массива с помощью ключей.
Способы объявления массива
literal notation []
1 2 |
var myArray = [1, 2, 3]; var myArray = ['apple', 'orange', 'banana', 'kiwi', 'tangerine', 'plum', 'grape']; |
С конструктором Array ()
1 2 |
var myArray = new Array (1, 2, 3); var myArray = new Array ('apple', 'orange', 'banana', 'kiwi', 'tangerine', 'plum', 'grape'); |
По сути, оба подхода одинаковы, но большинство людей используют literal notation [], так как она быстрее набирается и требует меньше кода.
Массивы могут хранить различные объекты — числа, строки, функции и даже другие массивы, а также внутри массивов вы можете свободно смешивать различные типы данных.
Массивы могут хранить:
- Primitive values
- Objects and Classes
- Functions
- Arrays
Примеры:
1 2 3 4 |
var number = [1, 2, 3, 4, 5] var strings = ['name', 'place', 'food' ] var functions = [ function x(){...}, finction y(){...} ] var mix = [ 12, 'niceplace', function xy(){...} ] |
Доступ к значениям массивов
Мы можем получить доступ к значениям массива, указав номер индекса. Номер индекса можно определить как расположение элемента в массиве. Чтобы получить значение, мы обращаемся к членам массива, используя номер индекса в квадратной скобке [].
Например :
1 2 |
var array = ['apple', 'orange', 'banana', 'kiwi', 'tangerine', 'plum', 'grape']; console.log(array[3]); |
Результат:
kiwi
Примечание: индексирование массивов начинается с 0, в приведенном выше примере, вы можете видеть, что array [0] возвращает первое значение массива, а array [1] возвращает второе значение. Чтобы проверить это, вы можете определить массив и использовать console.table для просмотра индексации массива.
Создание массива массивов
Массив массивов известен как многомерный массив или матрица. Они устроены так:
1 2 3 4 |
var FruitArray = [ ['apple', 'orange', 'banana'], ['kiwi', 'tangerine', 'plum', 'grape'] ]; |
Вы также можете создать многомерный массив с помощью конструктора Array () следующим образом:
1 2 3 4 |
var FruitArray = new Array( new Array('apple', 'orange', 'banana'), new Array('kiwi', 'tangerine', 'plum', 'grape') ); |
Элементы в многомерном массиве адресуются так же, как и отдельные массивы, но для разницы мы адресуем каждый элемент, используя несколько значений, начиная с самого внешнего массива.
Например, значение banana находится в индексе 0 самого внешнего массива и индексе 2 вложенного массива, поэтому мы будем называть его console.log(FruitArray[0][2])
Для лучшего понимания рассмотрим эту таблицу:
Добавление, удаление или замена элементов в массиве
Чтобы изменить или удалить данные из массива, вы должны знать, как добавлять или удалять элементы из массива. JavaScript предоставляет различные методы для добавления, удаления или изменения данных массива. Некоторые методы выполняют одну и ту же задачу, но используют другой подход.
Изменение / замена существующего значения на новое
Итак, вы создали массив и по какой-то причине хотите изменить конкретное значение массива. Это можно сделать с помощью оператора присваивания.
1 2 3 4 |
var MyArray = ['apple', 'orange', 'banana', 'kiwi', 'tangerine', 'plum', 'grape']; console.log(MyArray[2]); MyArray[2] = 'mango'; console.log(MyArray[2]); |
Результат:
Чтобы добавить или удалить значения без каких-либо проблем, JavaScript предоставляет различные методы работы и упрощения нашей работы.
Добавление элементов: методы push() и unshift()
Метод unshift() добавляет новые элементы в начало массива и возвращает новую длину.
Метод push() добавляет заданный элементы в последний элемент массива и возвращает длину нового массива.
Удаление элементов: методы pop() и shift()
Подобно push() и unshift() JavaScript предоставляет два полезных метода для удаления элемента с начала и с конца.
Метод shift() удаляет первый элемент из массива и возвращает этот удаленный элемент. Этот метод изменяет длину массива, для которого мы вызываем метод shift().
Метод pop() удаляет последний элемент массива и возвращает этот элемент.
Методы splice() и slice()
Теперь мы знаем, как добавить / удалить элемент из массива с начала или с конца. Пришло время понять, как можно добавлять, удалять или заменять элемент внутри массива.
Метод splice() — это встроенный в JavaScript метод, который используется для изменения содержимого массива путем удаления существующих элементов и / или добавления новых элементов.
1 |
MyArray.splice(index, remove_count, item_list); |
или
1 |
MyArray.splice(индекс_начала, количество_удаляемых_элементов, список_добавляемых_элементов); |
- index (индекс_начала): Обязательно. Целое число, указывающее, в какой позиции добавлять / удалять элементы. Используйте отрицательные значения, чтобы указать позицию от конца массива.
- remove_count (количество_удаляемых_элементов): Необязательно. Количество удаляемых элементов. Если установлено значение 0 (ноль), никакие элементы не будут удалены. И если он не передан, все элементы из указанного индекса будут удалены.
- item_list (список_добавляемых_элементов): Необязательно. Новые элементы для добавления в массив.
Метод slice() возвращает выбранные элементы в массиве как новый объект массива . Метод slice() выбирает элементы, начинающиеся с заданного начального аргумента, и заканчиваются заданным конечным аргументом, но не включают его.
1 |
MyArray.slice(начало, конец) |
- начало: целое число, указывающее, где начать выделение. Используйте отрицательные числа, чтобы выбрать конец массива.
- конец: целое число, указывающее, где завершить выделение. Если этот параметр не указан, будут выбраны все элементы от начальной позиции до конца массива. Используйте отрицательные числа, чтобы выбирать от конца массива.
1 2 |
var MyArrayInitial = ['apple', 'orange', 'banana', 'kiwi']; var MyArraySlice = MyArrayInitial.slice(1,3); |
15 методов для работы с массивами Javascript
Рассмотрим 15 полезных встроенных методов в массивы, которые помогут Вам в решении задач, связанных с массивами. Массивы JavaScript содержат несколько отличных методов, которые могут упростить наши усилия по разработке. Их знание может сэкономить нам время, а в некоторых случаях даже повысить производительность нашего кода.
some()
Иногда вам нужно проверить, есть ли в массиве хотя бы один элемент, который соответствует указанному условию. Как раз метод some() и проверяет наличие хотя бы одного элемента в массиве, который удовлетворяет условию, заданному в передаваемой функции.
some()
Функция выполняет callback
функцию один раз для каждого элемента массива , пока не найдет тот , где callback
функция возвращает true
. some()
Метод немедленно возвращает true
и не оценивает остальные элементы.
Если ни один элемент не вызывает callback()
возврата true
, some()
метод возвращается false
.
Например, чтобы проверить, имеет ли следующий массив хотя бы один элемент меньше 5:
1 2 3 4 5 |
var marks = [ 4, 5, 7, 9, 10, 3 ]; var lessThanFive = marks.some(currElem => currElem < 5); console.log(lessThanFive); // true |
every()
every() метод работает аналогично some() методу, но он проверяет соответствуют ли все элементы в массиве условию, которое реализованно callback-функцией.
1 2 3 4 5 |
const a = [10, 9, 8, 7, 6].every(item => item > 5); const b = [7, 6, 5].every(item => item > 5); console.log(a); // true console.log(b); // false |
reduce()
Синтаксис:
1 2 3 4 5 6 7 |
// только с callback функцией myArray.reduce(callbackFunc); // с callback функцией и первоначальным значением myArray.reduce(callbackFunc, initialValue); //initialValue - необязательный параметр |
Параметры callback функции
1 |
myArray.reduce(function(total, currentValue, currentIndex, arr), initialValue); |
reduce()
метод выполняет callback
-функцию один раз для каждого заданного значения, присутствующего в массиве, принимая 4 аргумента:
- total — обязательный параметр функции
- currentValue — обязательный параметр функции
- currentIndex — необязательный параметр функции
- array — необязательный параметр функции
1 2 3 4 5 6 7 8 9 10 11 |
var myArray = [ 4, 5, 7, 9, 10, 3 ]; var result1 = myArray.reduce((total, currentValue, currentIndex, array) => total + currentValue); console.log(result1); const initialValue = 10; //38 var result2 = myArray.reduce((total, currentValue, currentIndex, array) => total + currentValue, initialValue); console.log(result2); //48 |
Для первого результата result1 иллюстрация шагов расчета:
map()
Метод map()
создает новый массив, который заполнен результатами вычисления callback
-функции для каждого элемента в массиве.
Синтаксис:
1 |
myArray.map(callbackFunc(currentValue [, index [, array]]) [, thisArg]); |
callback
-функция получает до 3х аргументов:
currentValue
—index
—- и
array
—
1 2 3 |
var newArray = arr.map(function callback(element, index, array) { // Return value for new_array }[, thisArg]) |
Как и в случае с reduce(), callback
вызывается только для индексов массива, которым присвоены значения (включая undefined
).
Пример:
1 2 3 |
const numbers = [1, 2, 3, 4]; const doubled = numbers.map(item => item * 2); console.log(doubled); // [2, 4, 6, 8] |
Примечание: Всегда будьте осторожны при использовании map()
, помните, что при каждом вызове будет создаваться новый массив, если вам действительно не нужен массив, и вы просто пытаетесь выполнить итерацию, используйте forEach()
или for-of
вместо метода map()
.
flat()
Метод flat()
создает новый массив со всеми элементами суб-массива, объединяя субмассивы рекурсивно до заданной глубины. По умолчанию он «сглаживает» 1 уровень.
Синтаксис:
1 |
myArray.flat(depth) |
Пример
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const result1 = [1, 2, [3, 4]].flat(); console.log(result1); //[1, 2, 3, 4] const result2 = [1, 2, [3, 4, [5, 6]]].flat(); console.log(result2) //[1, 2, 3, 4, Array(2)] const result3 = [1, 2, [3, 4, [5, 6]]].flat(2); console.log(result3); //[1, 2, 3, 4, 5, 6] const result4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]].flat(Infinity); console.log(result4); //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
Обратите внимание: если мы хотим рекурсивно сгладить все уровни, мы можем передать Infinity в качестве аргумента функции.
filter()
Метод filter()
создает новый массив со всеми элементами, которые проходят тест-условие, которое реализовано с помощью callback
-функции.
filter()
метод принимает каждый элемент массива и применяет к нему условие (callback-function). Если это условие возвращает истину, элемент помещается в выходной массив. Если условие возвращает false, элемент не помещается в выходной массив.
Синтаксис:
1 2 3 |
var new_array = arr.filter(function callback(element, index, array) { // Return true or false }[, thisArg]) |
Синтаксис для filter
аналогичен map
, за исключением того, что функция обратного вызова должна возвращать true
— чтобы сохранить элемент или false
— чтобы не помещать элемент в итоговый массив.
В следующем примере нечетные числа «отфильтровываются», оставляя только четные числа:
1 2 3 |
var numbers = [1, 2, 3, 4]; var result = numbers.filter(item => item % 2 === 0); console.log(result); // [2, 4] |
еще пример:
1 2 3 4 5 6 7 8 9 10 11 12 |
const array = [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]; function isPrime (num) { for (let i = 2; num> i; i ++) { if (num% i == 0) { return false; } } return num > 1; } console.log( array.filter(isPrime) ); //[2, 3, 5, 7, 11, 13] |
forEach()
Метод forEach()
вызывает функцию один раз для каждого элемента массива в исходном порядке.
1 2 3 4 5 6 7 8 9 10 11 |
var fruits = ["apple", "orange", "cherry"]; fruits.forEach(myFunction); function myFunction(item, index) { console.log('item = ' + item + '; index = ' + index); } // Результат // item = apple; index = 0 // item = orange; index = 1 // item = cherry; index = 2 |
или еще пример
1 2 3 4 5 6 7 8 9 10 11 |
const array = [1, 2, 3, 4, 5]; array.forEach ((item) => console.log (item)); --------- Вывод --------- 1 2 3 4 5 |
При использовании forEach()
необходимо учитывать два важных момента:
- Нет другого способа остановить или прервать
forEach()
цикл, кроме создания исключения. forEach()
ожидает синхронногоcallback
, он не будет ждать выполнения обещаний.
Давайте посмотрим на пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
let ratings = [5, 4, 5]; let sum = 0; let sumFunction = async function (a, b) { return a + b; } ratings.forEach(async function(rating) { sum = await sumFunction(sum, rating); }) console.log(sum); --------- Output --------- 0 |
Несмотря на то, что мы ожидали, что переменная sum
накопит все значения в массиве и будет иметь значение 14
, мы получили в результате 0
, как если бы forEach()
оператор закончился без ожидания обещаний, и, таким образом, console.log
оператор был выполнен до того, как переменная sum
была обновлена. Поэтому внимательно относитесь к этой ситуации, так как она может привести к неожиданным результатам в вашем коде.
findIndex()
Метод findIndex()
возвращает индекс первого элемента массива, который удовлетворяет условию callback
функции.
Метод findIndex() выполняет функцию один раз для каждого элемента, присутствующего в массиве:
- Если он находит элемент массива, в котором функция возвращает истинное значение, findIndex() возвращает индекс этого элемента массива (и не проверяет остальные значения)
- В противном случае возвращается -1
Синтаксис:
1 |
arr.findIndex(callback( element[, index[, array]] )[, thisArg]) |
Пример:
1 2 3 4 5 6 7 8 9 10 11 |
function isPrime(num) { for (let i = 2; num > i; i++) { if (num % i == 0) { return false; } } return num > 1; } console.log([4, 6, 8, 9, 12].findIndex(isPrime)); console.log([4, 6, 7, 9, 12].findIndex(isPrime)); |
Результат:
1 2 3 4 5 |
--------- Output --------- -1 2 |
find()
Метод find()
аналогичен findIndex()
методу, но он возвращает значение первого элемента массива, который прошел условие callback
функции.
Метод find()
выполняет функцию один раз для каждого элемента, присутствующего в массиве:
- Если он находит элемент массива, в котором функция возвращает истинное значение,
find()
возвращает значение этого элемента массива (и не проверяет остальные значения) - В противном случае возвращается undefined
Синтаксис:
1 |
arr.find(callback(element[, index[, array]])[, thisArg]) |
Пример:
1 2 3 4 5 6 7 8 9 |
const inventory = [ {name: 'apples', quantity: 2}, {name: 'bananas', quantity: 0}, {name: 'cherries', quantity: 5} ]; const result = inventory.find( ({ name }) => name === 'cherries' ); console.log(result); |
Результат:
1 |
{name: "cherries", quantity: 5} |
sort()
Метод sort()
сортирует элементы массива.
Порядок сортировки может быть буквенным или числовым, по возрастанию (вверх) или по убыванию (вниз).
По умолчанию метод sort () сортирует значения, как строки в алфавитном порядке и по возрастанию.
Это хорошо подходит для кейсов со строками («яблоко» стоит перед «бананом»). Однако, если числа сортируются как строки, «25» больше «100», потому что «2» больше «1».
Из-за этого метод sort() выдаст неверный результат при сортировке чисел.
Вы можете исправить это, предоставив «функцию сравнения»
Синтаксис
1 |
arr.sort([compareFunction]) |
Пример
1 2 3 4 5 6 7 8 |
const numbers = [4, 2, 5, 1, 3]; numbers.sort((a, b) => a - b); console.log(numbers); --------- Output --------- > (5) [1, 2, 3, 4, 5] |
Всегда помните, что сортировка происходит в исходном массиве, поэтому:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const numbers = [4, 2, 5, 1, 3]; const numbers2 = numbers.sort((a, b) => a - b); console.log('numbers', numbers); console.log('numbers2', numbers2); console.log(numbers === numbers2); --------- Output --------- numbers > (5) [1, 2, 3, 4, 5] numbers2 > (5) [1, 2, 3, 4, 5] true |
Функция сортировки изменит существующий массив и вернет ссылку на тот же массив, и, таким образом, исходный массив и возвращенный массив будут одинаковыми.
concat()
Метод concat()
используется для соединения двух или более массивов.
Этот метод не изменяет существующие массивы, но возвращает новый массив, содержащий значения объединенных массивов.
Синтаксис:
1 |
const new_array = old_array.concat([value1[, value2[, ...[, valueN]]]]) |
Пример:
1 2 3 4 5 6 7 8 9 |
const letters = ['a', 'b', 'c']; const numbers = [1, 2, 3]; console.log(letters.concat(numbers)); --------- Output --------- > (6) ["a", "b", "c", 1, 2, 3] |
fill()
Метод fill()
заполняет указанные элементы в массиве статическим значением.
Вы можете указать позицию начала и окончания заливки. Если стартовый элемент не указан, будут заполнены все элементы.
Примечание: этот метод перезаписывает исходный массив.
Синтаксис:
1 |
arr.fill(value[, start[, end]]) |
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 |
const original = [1, 2, 3]; const result = original.fill(4); console.log('original', original); console.log('result', result); console.log(original === result); --------- Output --------- original > (3) [4, 4, 4] result > (3) [4, 4, 4] true |
includes()
Метод includes () определяет, содержит ли массив указанный элемент.
Этот метод возвращает истину, если массив содержит элемент, и ложь, если нет.
Обратите внимание, что метод includes()
чувствителен к регистру при сравнении строк и символов.
Синтаксис:
1 |
arr.includes(valueToFind[, fromIndex]) |
Пример:
1 2 3 4 5 6 7 8 |
console.log([1, 2, 3].includes(2)); console.log([1, 2, 3].includes(4)); --------- Output --------- true false |
reverse()
Метод reverse()
изменяет порядок элементов в массиве на обратный (реверсивный порядок). Функция транспонирует элементы массива, первый элемент станет последним, а последний — первым. Эта операция изменит исходный массив и вернет ссылку на него.
Синтаксис:
1 |
a.reverse() |
Пример:
1 2 3 4 5 6 |
console.log([1, 2, 3].reverse()); --------- Output --------- > (3) [3, 2, 1] |
flatMap()
Метод flatMap()
применяет функцию к каждому элементу массива, а затем сплющить результат в массив. Он совмещает flat()
и map()
в одной функции.
Синтаксис:
1 |
arr.flatMap(callback(currentValue[, index[, array]])[, thisArg]) |
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const array = [[1], [2], [3], [4], [5]]; const a = array.flatMap(arr => arr * 10); // Тот же самый результат, но с помощью двух функций .flat() and .map() const b = array.flat().map(arr => arr * 10); console.log('flatMap', a); console.log('flat & map', b); --------- Output --------- flatMap (5) [10, 20, 30, 40, 50] flat & map (5) [10, 20, 30, 40, 50] |
Objects / Объекты Javascript & JSON
В этом разделе будут описаны основы Javascript Objects, а также описан формат JSON и способы конвертации JSON в другие типы объектов
Javascript Objects
Объект — это вещь, с которой мы взаимодействуем, у нее есть свойства и методы. Object — это сердце объектно-ориентированного программирования.
Объект или Object в Javascript хранит данные с помощью пары ключ-значение (или key/value).
Как объявить объект в Javascript
Для инициализации пустого объекта используются фигурные скобки
1 |
var myObject = {}; |
Пример создания объекта с ключами и значениями:
1 2 3 4 |
var myObject = { color: "red", type: "matrix" }; |
Чтение отдельных значений объекта
Для того, чтобы обратиться к свойствам и методам объекта, можно использовать точечную нотацию
1 |
myObject.color |
или можно получить доступ к свойствам объекта с помощью квадратных скобок:
1 |
myObject["color"]; |
Обновление значения свойства объекта
1 |
myObject.color = "green"; |
или
1 |
myObject["color"] = "green"; |
Вложенные свойства объекта
Изменим структуру объекта в нашем примере, добавив еще один вложенный уровень со свойствами:
1 2 3 4 5 6 7 |
var myObject = { color: "red", params: { name: "My Object Name", description: "" } }; |
Чтение и запись вложенных значений
1 |
myObject.params.description = "My Object Description Example"; |
Добавление нового свойства к объекту
1 |
myObject.params.parant_id = 18495215126; |
Удаление существующего свойства в объекте
1 |
delete myObject.params; //удалит все вложенные значения в params |
Пример в формате HTML
Для упрощенного ознакомления с объектом рассмотрим пример. Создайте файл index.html и в него поместите скрипт:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>JS Object Example</title> </head> <body> <p>Пример Object в Javascript</p> <script> const person = { name: ['Bob', 'Smith'], age: 32, gender: 'male', interests: ['music', 'skiing'], bio: function() { console.log(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); }, greeting: function() { console.log('Hi! I\'m ' + this.name[0] + '.'); } }; </script> </body> </html> |
Запустите файл html, нажмите клавишу F12 и в консоли наберите команды:
1 2 3 4 5 |
person person.name[0] person.bio() person.greeting() person.interests |
Вы получите следующий результат:
Reference Value
Одни типы данных копируются по значению, а другие — по ссылке. Эта концепция лежит в основе бесчисленных ошибок.
JavaScript имеет 5 типов данных, которые копируются по значению: Boolean, null, undefined, String, и Number. Мы назовем их примитивными типами.
JavaScript имеет 3 типа данных, которые копируются по ссылке: Array, Function и Object. Технически все это объекты, поэтому мы будем называть их единым термином Объектом.
Переменным, которым присвоено непримитивное значение (или Объект), дается ссылка на это значение. Эта ссылка указывает на расположение объекта в памяти. Переменные на самом деле не содержат значения.
Объекты создаются в каком-то месте в памяти нашего компьютера. Когда мы пишем arr = []
, мы создали массив в памяти. Теперь переменная arr
содержит адрес, местоположение этого массива.
Рассмотрим пример, который пояснит вышеприведенное описание:
1 2 3 4 5 6 7 8 9 10 11 |
var a = "some text" var b = a //b копия a b = "different text" // эта операция не изменит a console.log("a = " + a); console.log("b = " + b); //=================================== var x = {color: "red"}; var y = x; // y ссылается на x (y is a reference to x) y.color = "green"; // изменит x и y !!! console.log("x.color = " + x.color); console.log("y.color = " + y.color); |
Результат:
JSON (JavaScript Object Notation)
JSON — это облегченный формат для хранения и передачи данных. Он часто используется, когда данные отправляются с сервера на веб-страницу. JSON работает на разных языках программирования, объекты javascript присущи только javascript. Формат JSON — это хранение сложной структуры данных в формате текста (строки).
Ниже приведены примеры, из которых видно, что внешне две структуры хранения данных очень похожи. Однако, в JSON ключи обязательно необходимо оборачивать в двойные кавычки.
Сравнение / Различие Javascript Object vs JSON
Пример Javascript Object
1 2 3 4 5 6 7 |
{ firstName: "Alexey", lastName: "Solodov", age: 34, height: 170, shoeSize: 41 } |
Пример JSON
1 2 3 4 5 6 7 |
{ "firstName": "Alexey", "lastName": "Solodov", "age": 34, "height": 170, "shoeSize": 41 } |
Сравнение типов данных
Преобразование JSON -> Object & Object -> JSON
Javascript имеет встроенную поддержку преобразования между JSON и объектом javascript. Чтобы преобразовать объект obj в данные JSON, вы можете использовать JSON.stringify(obj). Чтобы создать объект javascript из данных JSON data1, вы можете использовать JSON.parse(data1).
Пример преобразования Object -> JSON и JSON -> Object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// строка JSON var jsonPerson = '{"firstName":"Alexey","lastName":"Solodov","age":34,"height":170,"shoeSize":41}'; console.log(jsonPerson); //======================================= // объект JavaScript var objectPerson = { firstName: "Oleg", lastName: "Michailov", age: 29, height: 180, shoeSize: 43 }; console.log(objectPerson); //======================================= var resultParse = JSON.parse(jsonPerson); console.log(resultParse); //======================================= var resultStringify = JSON.stringify(objectPerson); console.log(resultStringify); |
Результат:
Копирование объекта Javascript
Примечание. Будьте осторожны при использовании этого метода, поскольку исходный объект должен быть безопасным для JSON. Поэтому может потребоваться какая-то обработка исключений, чтобы обеспечить безопасность в случаях, когда исходный объект не может быть преобразован в JSON.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// объект JavaScript № 1 var object1 = { firstName: "Oleg", lastName: "Michailov", age: 29, height: 180, shoeSize: 43 }; // объект JavaScript № 2 var object2 = JSON.parse(JSON.stringify(object1)); object2.age = 45; console.log(object1); console.log(object2); |
Результат:
Classes / Классы
В разделе будут приведено описание концепции классов Javascript. Также будет приведен пример framework для многократно используемой визуализации таблиц
Классы в JavaScript — это особый синтаксис прототипной модели наследования, которая является сопоставимым наследованием в объектно-ориентированных языках на основе классов.
Классы — это просто специальные функции, добавленные в ES6, которые предназначены для имитации ключевого слова class
из этих других языков. В JavaScript у нас могут быть class
объявления и class
выражения, но это просто функции. Как и все другие функции, здесь есть объявления функций и вызовы функций.
Классы служат шаблонами для создания новых объектов.
Самое важное, о чем следует помнить: классы — это обычные функции JavaScript, которые можно полностью воспроизвести без использования class
синтаксиса. Это специальный синтаксический сахар, добавленный в ES6, чтобы упростить объявление и наследование сложных объектов.
Синтаксический сахар (англ. syntactic sugar) в языке программирования — это синтаксические возможности, применение которых не влияет на поведение программы, но делает использование языка более удобным для человека.
Определение классов
Чтобы объявить класс, мы используем ключевое слово class
. Например, чтобы объявить простой класс, мы можем написать:
1 2 3 4 5 6 |
class Person{ constructor(firstName, lastName) { this.firstName= firstName; this.lastName = lastName; } } |
Сначала необходимо в коде определить класс, и только после этого можно его использовать в коде.
Тело класса определяется фигурными скобками. Мы определяем члены класса внутри скобок. Тело класса выполняется в строгом режиме (strict mode), поэтому все, что определено в строгом режиме, применяется к определению класса, поэтому мы не можем определять переменные без ключевого слова перед ним, например var, let или const, и многие другие правила применяются при определении класса.
У классов в JavaScript также есть constructor
метод, который позволяет нам устанавливать поля, когда объект создается с помощью class
. В каждом классе может быть только один constructor
метод. Если их больше одного, возникнет SyntaxError
.
constructor
также может вызвать super
метод для вызова constructor
суперкласса, если класс расширяет родительский класс.
Методы без ключевого слова static
являются прототипными методами класса. Они вызываются после создания объекта с использованием new
ключевого слова. Например, в следующем классе есть только прототипные методы:
1 2 3 4 5 6 7 8 9 10 11 12 |
class Person{ constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } get fullName(){ return `${this.firstName} ${this.lastName}`; } sayHi(){ return `Hi, ${this.firstName} ${this.lastName}`; } } |
В Person
классе выше fullName
и sayHi
являются прототипами методов. Вызываются они так:
1 2 |
const person = new Person('Jane', 'Smith'); person.fullName(); // 'Jane Smith' |
Статические методы — это методы помеченные ключевым словом static
, их можно вызывать без создания объекта из класса с помощью new
ключевого слова. Например, у нас может быть что-то вроде следующего:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } get fullName() { return `${this.firstName} ${this.lastName}`; } sayHi() { return `Hi, ${this.firstName} ${this.lastName}`; } static personCount() { return 3; } } |
Мы можем вызвать personCount
функцию без использования new
ключевого слова для создания экземпляра класса. Итак, если мы напишем:
1 |
Person.personCount //Получим 3 |
this
Значение внутри прототипических методов будет значение объекта. Для статических методов значение this
имеет класс, в котором находится статический метод, в качестве значения.
Getters and Setters / Геттеры и сеттеры
Классы JavaScript могут иметь функции получения (get) и установки (set).
Геттеры, как следует из названия, — это метод, который позволяет нам получать некоторые данные из класса.
Сеттеры — это методы, которые дают нам возможность устанавливать некоторые поля класса.
Мы обозначаем геттер-функции get
ключевым словом, а сеттеры — set
ключевым словом. Например, мы можем написать класс, у которого есть геттеры и сеттеры, как показано ниже:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class Person { constructor(firstName, lastName) { this._firstName = firstName; this._lastName = lastName; } get fullName() { return `${this.firstName} ${this.lastName}` } get firstName() { return this._firstName } get lastName() { return this._lastName } sayHi() { return `Hi, ${this.firstName} ${this.lastName}` } set firstName(firstName) { this._firstName = firstName; } set lastName(lastName) { this._lastName = lastName; } } |
Затем, когда мы используем new
ключевое слово для создания Person
объекта, мы можем использовать их следующим образом:
1 2 3 4 |
const person = new Person('Jane', 'Smith'); person.firstName = 'John'; person.lastName = 'Doe'; console.log(person.firstName, person.lastName) |
Так как у нас есть методы получения и установки значений, то мы можем использовать их , чтобы установить данные непосредственно в члены класса firstName
и lastName
в Person
классе.
В функциях установки, которые начинаются с ключевого слова set
, когда мы присваиваем им значение, оно передается в параметры и устанавливается в члене класса.
В функциях получения, которые обозначены, get
мы возвращаем значения членов, которые запускают связанную get
функцию для значения.
JavaScript Inheritance / Наследование
В JavaScript мы можем создавать классы, в которых свойства могут быть включены в свойства дочернего класса.
Итак, у нас может быть класс высокого уровня, который содержит свойства, общие для всех дочерних классов, а дочерний класс может иметь свои собственные особые свойства, которых нет ни в каких других классах.
Например, если у нас есть Animal
класс с общими свойствами и методами, такими как name
и eat
метод, тогда Bird
класс может просто наследовать общие свойства в Animal
классе. Их не нужно снова определять в Bird
классе.
Мы можем написать следующее, чтобы выполнять наследование в JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Animal { constructor(name) { this.name = name; } eat() { console.log('eat'); } } class Bird extends Animal { constructor(name, numWings) { super(name); this.numWings = numWings; } } const bird = new Bird('Joe', 2); console.log(bird.name); bird.eat(); |
В приведенном выше примере у нас есть родительский класс Animal
, у которого есть eat
метод, который будет у всех классов extends
из Animal
, поэтому eat
не нужно определять снова.
У нас есть Bird
класс, расширяющий Animal
класс. Обратите внимание, что в constructor
в Bird
классе, у нас есть super()
вызов функции для вызова конструктора класса родителя для заполнения свойства родительского класса в дополнении к свойствам класса ребенка.
Классы не могут расширять обычные объекты, которые нельзя построить с помощью new
ключевого слова. Если мы хотим наследовать от обычного объекта, мы должны использовать Object.setPrototypeOf
функцию, чтобы установить класс для наследования от обычного объекта. Например:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
const Animal = { eat() { console.log(`${this.name} eats`); } } class Cat{ constructor(name) { this.name = name; } } class Chicken{ constructor(name) { this.name = name; } } Object.setPrototypeOf(Cat.prototype, Animal); Object.setPrototypeOf(Chicken.prototype, Animal); let cat = new Cat('Bob'); let chicken = new Chicken('Joe'); cat.eat(); chicken.eat(); |
Если мы запустим приведенный выше пример кода, мы сможем увидеть Bob eats
и Joe eats
, потому что мы унаследовали eat
функцию от Animal
объекта.
this Ключевое слово
this
Ключевое слово позволяет получить доступ к свойствам текущего объекта внутри объекта, если вы не используете функции стрелок.
Как видно из приведенного выше примера, мы можем получить свойства экземпляра дочернего и родительского классов в объекте.
Loops and Template Strings / Циклы и строки шаблона
В этом разделе будут рассмотрены 2 метода перебора массивов и использование строк шаблонов для создания динамического HTML
Циклы для перебора массива или объекта — Loops for Array & Object (For and ForEach)
Одна из самых фундаментальных программных конструкций — это цикл for. Все языки имеют некоторую реализацию цикла for, и forEach и JavaScript ничем не отличаются.
По мере развития языка у нас появилась возможность перебирать массивы и объекты. Объекты JavaScript также являются массивами, что позволяет легко получать значения через индекс, а именно по числовому ключу или имени.
Базовый цикл For
Циклы for в JavaScript перебирают каждый элемент массива. Массивы JavaScript начинаются с нуля, что означает, что на первый элемент ссылаются с индексом 0.
Ссылки на элементы в массивах выполняются с помощью числового индекса, начиная с нуля и заканчивая длиной массива минус 1. Синтаксис для цикла FOR
1 2 3 |
for (startIndex; condition_loop; increment) { // code to be executed } |
Как видите, в операторе цикла for используются три выражения: startIndex, condition_loop и increment. Последнее выражение выполняется в конце выполнения каждого цикла. Обычно используется для увеличения индекса.
Пример
1 2 3 4 |
var color = ['green','red','orange']; for (var i=0; i<color.length; i++) { console.log(color[i]); } |
Результат:
1 2 3 |
green red orange |
Если вам нужно перебрать свойства или поля второго уровня, вы можете использовать вложенные циклы. Самое главное, что вам нужно отслеживать — это объявление отдельной переменной индекса.
Пример
1 2 3 4 5 6 7 8 9 10 |
let myArray = [ {"child": ["one", "two", "three", "four"]}, {"child": ["five", "six", "seven", "eight"]} ]; for(let i = 0; i < myArray.length; i++){ let childArray = myArray[i].child; for(let j = 0; j < childArray.length; j++){ console.log(childArray[j]); } } |
Результат:
Если вам нужно остановить цикл, вы можете использовать оператор break или установить для индекса длину массива или значение, при котором condition_loop больше не будет истинным.
1 2 3 4 5 6 7 |
var myArray = [...]; for(let i = 0; i < myArray.length; i++){ if([condition met]){ break; } console.log(myArray[i]); } |
Если вы опускаете оператор условия (condition_loop), то вы должны использовать break для завершения цикла for. В противном случае создается бесконечный цикл, поскольку критерий останова цикла никогда не выполнится.
JavaScript Array — Метод forEach
Традиционный цикл for легко понять, но иногда синтаксис может быть утомительным. Например, вложенный цикл требует объявления новых переменных с вложенной областью видимости. Современный JavaScript добавил метод forEach к объекту массива.
1 |
Array.prototype.forEach(callback([value, index, array]), thisArg) |
Этот метод является членом прототипа массива и использует функцию обратного вызова, чтобы вы могли встроить любую настраиваемую логику в итерацию.
Функция обратного вызова forEach фактически принимает три аргумента:
- element value — значение элемента
- element index — индекс элемента
- array being traversed
Элемент — это текущее значение элемента. Думайте об этом как о myArray [i]. Следующее значение — это индекс, который коррелирует с i в предыдущих примерах.
Последний параметр — это копия повторяемого массива.
Если вы не объявите переменную для любого из этих параметров, они просто не будут выделены. Например, в большинстве случаев использования метода forEach просто используется элемент и игнорируется индекс и массив. Элемент является наиболее важным значением при итерации, поэтому вы всегда должны объявлять параметр элемента.
После метода обратного вызова метод forEach также принимает необязательный аргумент thisArg. Если предоставлен, он используется как ссылка this в методе обратного вызова. В противном случае это не определено.
Пример
1 2 3 4 5 6 7 |
let myArray = [ {"child": ["one", "two", "three", "four"]}, {"child": ["five", "six", "seven", "eight"]} ]; myArray.forEach(function(element) { console.log(element); }); |
Результат
Улучшим код
1 2 3 4 5 6 7 8 9 |
var myArray = [ {"child": ["one", "two", "three", "four"]}, {"child": ["five", "six", "seven", "eight"]} ]; myArray.forEach(childArray => { childArray.child.forEach(childElement => { console.log(childElement); }); }); |
Результат
Недостатком использования forEach является то, что его нельзя остановить, как оператор break в цикле for. Вы можете создать исключение, но это крайний случай.
Вы также должны знать, изменяются ли элементы массива во время выполнения метода forEach, изменения не обрабатываются. Массив — это те же значения с момента начала выполнения forEach.
forEach работает только с массивами, а это значит, что вам нужно проявить немного творчества, если вы хотите перебирать объекты.
Цикл по объектам в JavaScript
Лучший способ перебрать объекты — сначала преобразовать объект в массив. Затем вы просматриваете массив.
Вы можете преобразовать объект в массив тремя способами:
Object.keys
Object.values
Object.entries
Object.keys
Object.keys
создает массив, содержащий свойства объекта. Вот пример
1 2 3 4 5 6 7 |
const fruits = { apple: 28, orange: 17, pear: 54, } const keys = Object.keys(fruits) console.log(keys) // [apple, orange, pear] |
Object.values
Object.values
создает массив, содержащий значения каждого свойства объекта. Вот пример:
1 2 3 4 5 6 7 |
const fruits = { apple: 28, orange: 17, pear: 54, } const values = Object.values(fruits) console.log(values) // [28, 17, 54] |
Object.entries
Object.entries
создает массив массивов. Каждый внутренний массив состоит из двух элементов. Первый элемент — это собственность; второй пункт — это стоимость.
Вот пример:
1 2 3 4 5 6 7 8 9 10 11 12 |
const fruits = { apple: 28, orange: 17, pear: 54, } const entries = Object.entries(fruits) console.log(entries) // [ // [apple, 28], // [orange, 17], // [pear, 54] // ] |
Больше всего мне нравится из трех, Object.entries
потому что вы получаете и ключ, и значение свойства.
Цикл по массиву
После того, как вы преобразовали объект в массив с помощью Object.keys
, Object.values
или Object.entries
, вы можете перебрать его, как если бы это был обычный массив.
1 2 3 4 5 6 7 8 9 |
// Looping through arrays created from Object.keys const keys = Object.keys(fruits) for (const key of keys) { console.log(key) } // Results: // apple // orange // pear |
Если вы используете, Object.entries
вы можете захотеть деструктурировать массив на его ключ и свойство.
1 2 3 4 5 6 7 |
for (const [fruit, count] of entries) { console.log(`There are ${count} ${fruit}s`) } // Result // There are 28 apples // There are 17 oranges // There are 54 pears |
JavaScript Template Literals (Template Strings) / Строки шаблона
JavaScript Template Literals (Template Strings) позволяют использовать строки или встроенные выражения в виде строки. Они заключены в обратные кавычки .
Пример
1 2 |
const name = 'Jack'; console.log(`Hello ${name}!`); // Hello Jack! |
Еще одна особенность шаблонных литералов или шаблонных строк — это возможность иметь многострочные строки без каких-либо забавных дел.
Ранее с обычной строкой мы избегали бы новых строк следующим образом:
1 2 3 |
var text = "hello there, \ how are you + \ "; |
Это становится непростой задачей. В ES6 теперь мы можем использовать строки шаблона. Можно создать разметку HTML в виде строки. Здесь вы можете использовать обратные кавычки и использовать свойства объекта как переменной.
Давайте определим объект:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const person = { name: 'Wes', job: 'Web Developer', city: 'Hamilton', bio: 'Wes is a really cool guy that loves to teach web development!' } // And then create our markup: const markup = ` <div class="person"> <h2> ${person.name} </h2> <p class="location">${person.location}</p> <p class="bio">${person.bio}</p> </div> `; |
Теперь мы можем взять эту строку и поместить ее в существующий элемент на HTML-странице. Просто для примера вы можете использовать пустую страницу, где единственным существующим элементом, который у нас есть на странице, является document.body
и затем мы можем поместить переменную в inner.HTML
:
1 |
document.body.innerHTML = markup; |
Примечание: Важно отметить, что каждый раз, когда вы создаете HTML, и данные поступают от пользователя, нам нужно экранировать эти данные.
Цикл с использованием шаблонных строк
Еще одна удивительная особенность шаблонных строк заключается в том, что вы можете вкладывать их друг в друга. Что делать, если у меня есть массив, dogsи я хочу перебрать его и получить элемент списка для каждого из них?
1 2 3 4 5 |
const dogs = [ { name: 'Snickers', age: 2 }, { name: 'Hugo', age: 8 }, { name: 'Sunny', age: 1 } ]; |
Мы можем вкладывать строки шаблона прямо в него.
1 2 3 4 5 |
const markup = ` <ul class="dogs"> ${dogs.map(dog => * ${dog.name} is ${dog.age * 7})} </ui> `; |
Web Requests, Callbacks and Promises / Веб-запросы, обратные вызовы и обещания
В этом разделе будет описаны приемы использования данных из веб-службы с помощью XMLHTTPRequest, а также будет разобрано как реализовать обратные вызовы (Callbacks) и обещания (Promises)
JavaScript Http Web Requests
HTTP запрос с помощью функции XMLHttpRequest()
XMLHttpRequest
(XHR) — это встроенный объект браузера для выполнения HTTP-запросов в JavaScript.- Устарел по сравнению с более современным методом
fetch
С помощью объекта XMLHttpRequest — вы можете:
- Обновить веб-страницу без перезагрузки страницы
- Запросить данные с сервера — после загрузки страницы
- Получать данные с сервера — после загрузки страницы
- Отправка данных на сервер — в фоновом режиме
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
function getData(url) { let myRequest = new XMLHttpRequest(); myRequest.open("GET", url); myRequest.onload = function() { // if and status code is OK if (myRequest.status === 200) { console.log('\nRaw: '); // DEBUG console.log(myRequest.responseText); // DEBUG const data = JSON.parse(myRequest.responseText); // convert to obj. console.log('\nConverted:'); // DEBUG console.log(data); // DEBUG // if status code is not OK } else { console.log('Something went wrong'); } } myRequest.onerror = function() { return myRequest.statusText; } myRequest.send(); } let url = "https://restcountries.eu/rest/v2/all"; let resultData = getData(url); console.log(resultData); |
Алгоритм:
- Создается объект XMLHttpRequest
- Передаем параметры для GET-запроса по заданному URL
- Отправляем запрос
- Если сервер вернул ответ с кодом не 200, то это ошибка (обработать ошибку)
- Свойство responseText возвращает ответ сервера в виде текстовой строки.
Синтаксис:
1 2 3 4 |
myRequest.open(method, URL, async, user, password); // async – если установлено в false, то запрос производится синхронно, // если true – асинхронно. // user, password – логин и пароль для HTTP-авторизации (опционально). |
Методы объекта XMLHttpRequest
Method | Описание |
---|---|
new XMLHttpRequest() | Creates a new XMLHttpRequest object |
abort() | Cancels the current request |
getAllResponseHeaders() | Returns header information |
getResponseHeader() | Returns specific header information |
open(method, url, async, user, psw) | Specifies the request
method: the request type GET or POST |
send() | Sends the request to the server Used for GET requests |
send(string) | Sends the request to the server. Used for POST requests |
setRequestHeader() | Adds a label/value pair to the header to be sent |
Свойства объекта XMLHttpRequest
Property | Описание |
---|---|
onreadystatechange | Defines a function to be called when the readyState property changes |
readyState | Holds the status of the XMLHttpRequest. 0: request not initialized 1: server connection established 2: request received 3: processing request 4: request finished and response is ready |
responseText | Returns the response data as a string |
responseXML | Returns the response data as XML data |
status | Returns the status-number of a request 200: «OK» 403: «Forbidden» 404: «Not Found» For a complete list go to the Http Messages Reference |
statusText | Returns the status-text (e.g. «OK» or «Not Found») |
HTTP запрос с помощью функции Fetch()
Краткое описание Fetch
- Fetch — это новый API, который предоставляет более мощный и гибкий набор функций (более современный по сравнению с XHR)
- Он не поддерживается старым браузером (может быть полифиллирован), но очень хорошо поддерживается среди современных
- Fetch API основан на Promises, что обеспечивает более простой и понятный API, избегая ада обратных вызовов.
Синтаксис
1 |
let promise = fetch(url, [options]); |
Пример 1
1 2 3 4 5 6 7 8 9 10 |
let url = "https://restcountries.eu/rest/v2/all"; let response = await fetch(url); if (response.ok) { let data = await response.json(); console.log(data); } else { alert("Error", response.status); } |
Пример 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
async function getCountries(url) { const response = await fetch(url); const countries = await response.json(); return countries; } let url = 'https://restcountries.eu/rest/v2/all'; getCountries(url) .then((countries) => { console.log(countries); }) .catch((reason) => { console.log(reason.message); }); |
response.json()
— это метод объекта Response, который позволяет извлекать объект JSON из ответа. Метод возвращает обещание (Promise), так что вы должны ждать JSON:
await response.json()
.
Объект ответа предлагает множество полезных методов (все возвращающие обещания):
response.json()
возвращает обещание, преобразованное в объект JSONresponse.text()
возвращает обещание, преобразованное в необработанный текстresponse.formData()
возвращает обещание, разрешенное в FormDataresponse.blob()
возвращает обещание, разрешенное в blob (файловый объект сырых данных)response.arrayBuffer()
возвращает обещание, разрешенное в ArrayBuffer (необработанные общие двоичные данные)
Вызов fetch()
запускает запрос и возвращает обещание. Когда запрос завершается, обещание преобразуется в объект ответа. Из объекта ответа вы можете извлекать данные в нужном вам формате: JSON, необработанный текст, Blob.
Поскольку fetch()
возвращает обещание, вы можете упростить код, используя async/await
синтаксис.
HTTP запрос с помощью функции Axios()
todo
Функция обратного вызова (Javascript callback-функция)
callback (функция обратного вызова) — это функция, переданная в качестве аргумента другой функции.
В JavaScript функции являются объектами. Поэтому функции могут принимать в качестве аргументов другие функции, а также функции могут возвращать в качестве результата функции. Функции, которые это умеют, называются функциями высшего порядка. А любая функция, которая передается как аргумент, называется callback-функцией. (Источник: https://ru.hexlet.io/blog/posts/javascript-what-the-heck-is-a-callback)
В Javascript нельзя просто вызывать функции в нужном порядке и надеяться, что они в любом случае выполнятся в том же порядке. Callback функции позволяют нам быть уверенными в том, что определенный код не начнет исполнение до того момента, пока другой код не завершит исполнение.
Используя обратный вызов, вы можете вызвать функцию myCalculator
с помощью обратного вызова и позволить функции калькулятора выполнить обратный вызов после завершения расчета:
1 2 3 4 5 6 7 8 9 10 |
function myDisplayer(some) { document.getElementById("demo").innerHTML = some; } function myCalculator(num1, num2, myCallback) { let sum = num1 + num2; myCallback(sum); } myCalculator(5, 5, myDisplayer); |
Когда вы передаете функцию в качестве аргумента, помните, что нельзя использовать скобки.
Асинхронный JavaScript
Если вы создаете функцию для загрузки внешнего ресурса (например, скрипта или файла), вы не можете использовать контент, пока он не будет полностью загружен.
Здесь лучше всего использовать Callback функцию.
Следующий пример загружает HTML-файл ( template.html
) и отображает HTML-файл на веб-странице после полной загрузки файла:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function myDisplayer(some) { document.getElementById("demo").innerHTML = some; } function getFile(myCallback) { let req = new XMLHttpRequest(); req.open('GET', "template.html"); req.onload = function() { if (req.status == 200) { myCallback(this.responseText); } else { myCallback("Error: " + req.status); } } req.send(); } getFile(myDisplayer); |
JavaScript Promises — Resolve, Reject, and Chaining
JavaScript Promise Object — специальный объект, который содержит как производящий код (producing code), так и вызовы потребляющего кода (consuming code). Promise позволяют удобно организовать использование асинхронного кода.
Синтаксис:
1 2 3 4 5 6 7 8 9 10 11 12 |
let myPromise = new Promise(function(myResolve, myReject) { // "Producing Code" (May take some time) myResolve(); // when successful myReject(); // when error }); // "Consuming Code" (Must wait for a fulfilled Promise) myPromise.then( function(value) { /* code if successful */ }, function(error) { /* code if some error */ } ); |
Когда исполняемый код получает результат, он должен вызвать один из двух обратных вызовов:
Result | Call |
---|---|
Success | myResolve(result value) |
Error | myReject(error object) |
Свойства объекта Promise
Объект Promise поддерживает два свойства: state и result.
JavaScript Promise может находиться в трех состояниях:
- Pending (В ожидании) — Пока объект Promise «pending» (работает), результат не определен (undefined).
- Fulfilled (Выполнено) — Когда объект Promise «выполнен», результатом является value.
- Rejected (Отклонено) — Когда объект Promise «отклонен», результатом является объект error.
Таблица state и result:
myPromise.state | myPromise.result |
---|---|
«pending» | undefined |
«fulfilled» | a result value |
«rejected» | an error object |
Для обработки обещаний необходимо использовать метод Promise.
1 2 3 4 |
myPromise.then( function(value) { /* code if successful */ }, function(error) { /* code if some error */ } ); |
Promise.then()
принимает два аргумента: callback для успеха и еще один callback для отказа. Оба являются необязательными, поэтому вы можете добавить обратный вызов только для успеха или неудачи.
Пример использования promise:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
function myDisplayer(some) { document.getElementById("demo").innerHTML = some; } let myPromise = new Promise(function(myResolve, myReject) { let req = new XMLHttpRequest(); req.open('GET', "mycar.htm"); req.onload = function() { if (req.status == 200) { myResolve(req.response); } else { myReject("File not Found"); } }; req.send(); }); myPromise.then( function(value) {myDisplayer(value);}, function(error) {myDisplayer(error);} ); |
Подборка видео
Asynchronous JavaScript — Async и Await function
Async и await позволяют нам писать асинхронный код JavaScript, который читается гораздо более четко. Async / Await на самом деле является просто синтаксическим сахаром, обеспечивающим способ создания кода, о котором легче думать, без изменения базовой динамики.
async и await упрощают написание обещаний
async заставляет функцию возвращать обещание
await заставляет функцию ждать обещания
Async Синтаксис
Ключевое слово async
перед функцией заставляет функцию возвращать обещание:
Пример:
1 2 3 4 5 6 7 8 |
async function myFunction() { return "Hello"; } myFunction().then( function(value) {myDisplayer(value);}, //code if successful function(error) {myDisplayer(error);} //code if some error ); |
Await Синтаксис
Ключевое слово await
перед функцией заставляет функцию ждать обещания:
let value = await promise;
Ключевое слово await
можно использовать только внутри async
функции.
Пример «Ожидание файла»
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
async function getFile() { let myPromise = new Promise(function(myResolve, myReject) { let req = new XMLHttpRequest(); req.open('GET', "mycar.html"); req.onload = function() { if (req.status == 200) {myResolve(req.response);} else {myResolve("File not Found");} }; req.send(); }); document.getElementById("demo").innerHTML = await myPromise; } getFile(); |
Асинхронные функции приостанавливаются при каждом await выражении
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
function who() { return new Promise(resolve => { setTimeout(() => { resolve('Hi!'); }, 200); }); } function what() { return new Promise(resolve => { setTimeout(() => { resolve('It is async function example.'); }, 300); }); } function where() { return new Promise(resolve => { setTimeout(() => { resolve('Try it!'); }, 500); }); } async function msg() { const a = await who(); const b = await what(); const c = await where(); console.log(`${ a } ${ b } ${ c }`); } msg(); // Hi! It is async function example. Try it! |
В приведенном выше примере каждый шаг выполняется последовательно, при этом каждый дополнительный шаг ожидает разрешения или отклонения предыдущего шага перед продолжением. Если вместо этого вы хотите, чтобы шаги выполнялись параллельно, вы можете просто использовать Promise.all дождаться исполнения всех обещаний: