Основы ES 6
2015 год - появление современного JavaScript. принят стандарт EcmaScript 6, он же EcmaScript 2015. До этого последний раз JavaScript обновлялся двенадцать лет назад — в 2009 году, когда появился EcmaScript5. Впрочем, тогда изменения были не такими значительными.
Нововведения EcmaScript 6
Ключевые слова let и const
Основное их отличие — блочная область видимости.
При этом let — переменная, а const — переменная, значение которой не меняется.
Впрочем, про не меняется значение, это не всегда справедливо. Написать const a = 1; a++; нельзя. а сonst a = 1; return a + 1; — можно. Здесь главное не присваивать константе другое значение (а++ это то же самое, что а = а + 1). Соответственно, массивы, объявленные через const, могут изменяться с использованием метода push, и такой код. меняющий массив, объявленый через сonst, тоже будет вполне валидным
const arr = [1, 1, 1, 1];
arr.map(a => a + 1); // [2, 2, 2, 2];
Чем не угодил var
Современный код пишут команды разработчиков, а если один, то он, как правило, использует сторонние решения. Поэтому использование переменной, область видимости которой является глобальной, небезопасно с точки зрения возникновения конфликта имён.
В качестве преимущества использования let традиционно приводят такой код:
for(var i = 0; i < 3; i++) {
setTimeout(function(){
console.log(i)
}, 100)
}
Результатом будут три тройки.
Аналогичный код с объявлением переменной через let выведет числа от 0 до 3:
for(let i = 0; i < 3; i++) {
setTimeout(function(){
console.log(i)
}, 100)
}
Впрочем, аргументы против всеобщего перехода на let & const тоже серьёзные. Один из них - необходимость поддерживать старые браузеры, в которых новый код работать не будет вообще. Не ухудшит внешний вид, как, например, использование неподдерживаемых css-свойств, а приведёт к полной неработоспособности сайта.
Стрелочные функции
В JavaScript функции являются объектами. Это удобно. Можно их присваивать переменным, передавать в качестве параметров в другие функции, возвращать в качестве результата выполнения других функций. Но необходимость использования ключевых слов function и
return увеличивала количество кода.
рассмотрим функцию:
function square(a) {
return a * a;
}
Всё, что она делает - возводит переданный параметр в квадрат. Её полезное действие описывается тремя символами a * a. Всё остальное - необходимость следовать синтаксису языка.
Тот же код, записаннй при помощи стрелочной функции стал короче и проще:
const square = a => a * a;
Сокращение количества кода выглядит ещё нагляднее в более сложном коде. Напишем функцию, которая возвращает наибольшее непарное число из массива строк:
var arr = ["1", "2", "3", "4", "5"];
var res = arr.map(a => +a)
.filter(a => a%2)
.reduce((max, val) => Math.max(max, val), 0);
Тот же код, записанный традиционным способом, увеличится в размерах примерно в три раза.
*Дополнено.
Для поиска максимального значения автор предлагает использовать функцию
arr.reduce((max, val) => Math.max(max, val), 0);
На самом деле можно намного проще:
Math.max.apply(null, arr)
И ещё проще:
Math.max(...arr)
Справедливости ради отмечу, что перечисленные подходы рассматриваются в других видео.
Ещё одна особенность стрелочных функций - способность сохранять контекст, который был доступный в исходной функции.
Здесь можно вспомнить тему по основам ООП в которой для передачи контекста во внутренню функцию предлагалось использовать методы bind, call,apply, или кешировать контекст через переменную that.
Ещё один способ - использовать стрелочную функцию.
Пример. Обычная функция:
var a = {
prop: "a",
f: function () {
var fn = function (){
console.log(this.prop);
};
fn();
}
};
a.f() // undefined
Стрелочная функция
var a = {
prop: "a",
f: function () {
var fn = () => {
console.log(this.prop);
};
fn();
}
};
a.f() // а
Также у стрелочных функций нет свойства prototype и они не могут быть вызваны с new. Это небольшие легковесные функции, которые удобно использовать для решения небольших задач.
Параметры по умолчанию
Позволяют вызывать функцию с параметрами или без. Во втором случае подставится параметр по умолчанию.
Пример:
function fn(count = 10, start = 1) {
return start * count;
}
fn() // 10
fn(undefined, 2) // 20
fn(3, 5) // 15
Параметр по умолчанию может быть и один из нескольких, обычно его указывают последним. Параметры по умолчанию заменяют отсутствующие параметры, или те, значение которых указано как undefined.
Параметры по умолчанию могут иметь любой тип.
Если в качестве параметра по умолчанию указан объект, он не будет смешиваться с объектом, который передан функции, даже если у последнего отсутствуют некоторые свойства. Объект передаётся полностью, а не по частям.
Rest параметр
В JavaScript функции можно передать любое количество аргументов независимо от числа указанных параметров. Все они находятся в псевдомассиве arguments, доступном внутри функции. Напишем функцию, которая находит максимальный аргумент из числа переданных ей. Раньше, до 2015 года это могло выглядеть так:
function max() {
var numbers = Array.from(arguments);
var numMax = Math.max(...numbers);
return numMax;
}
max(1,2,3,4,5);
Собственно, до 2015 года всё было совсем иначе.
Строка Array.from(arguments);, которая позволяет перевести псевдомассив в массив, на самом деле до 2015 года выглядела как Array.prototype.slice.call(arguments);.
Строка Math.max(...numbers);, которая ищет максимальное значение в массиве, выглядела как Math.max.apply(null, numbers).
Зато уже тогда был псевдомассив arguments. Хоть что-то.
Сейчас псевдомассив arguments остался, но дополнительно появился rest-параметр. Выглядит так
function max(...numbers) {
return numbers;
}
max(1,2,3,4,5); // [1, 2, 3, 4, 5]
и представляет собой обычный настоящий массив, а не псевдомассив.
Кстати, если при запуске функции будет только один аргумент, он всё равно будет единственным элементом массива, а если запускать функцию без аргументов, в rest-параметре будет пустой массив.
Перед rest-параметром можно указать обычные параметры функции.
function max(a, b, ...numbers) {
return numbers;
}
max(1,2,3); // [3]
Ограничения при работе с rest-параметрами
- rest-параметр должен идти последним в функции
- нельзя указывать больше одного rest-параметра
Оператор расширения (spread-оператор)
spread-оператор раскладывает массив на список независимых элементов.
Примеры использования:
Объединение массивов:
var arr = [3, 4];
var arr1 = [1, 2, ...arr, 5, 6];
Поиск максимального значения
Из одного массива
var arr = [1, 2, 3, 4, 5];
var max = Math.max(...arr);
Из двух массивов и дополнительных элементов
var arr1 = [1, 2, 3, 4, 5];
var arr2 = [6, 7, 8, 9, 10];
var max = Math.max(...arr1, ...arr2, 11, 12);
Копирование массива
var arr = ['a', 'b', 'c'];
var arr2 = [...arr];
Преобразование строки в массив
var str = "hello";
var arr = [...str];
Удаление дубликатов из массива.
Вместо
var arr = ['a', 1, 'a', 2, '1'];
var unique = Array.from(new Set(arr))
unique
Можно написать
var arr = ['a', 1, 'a', 2, '1'];
var unique = [...new Set(arr)];
unique
Дополнительный источник:
https://habr.com/ru/company/ruvds/blog/348612/
Деструктуризация объектов
Предположим у нас есть объект
const person = {
firstName: "Peter",
lastName: "Smit",
age: 23
}
И мы хотим получить из него имя и возраст. Раньше это делали так:
const firstName = person.firstName;
const age = person.age;
Результат:
firstName // "Peter"
age // 23
Сейчас можно проще
const person = {
firstName: "Peter",
lastName: "Smit",
age: 23
}
const {firstName, age} = person;
firstName // "Peter"
age // 23
Предположим, объект содержит внутренние объекты
const person = {
name: {
first: "Peter",
last: "Smit",
},
age: 23
}
Его деструктуризация выглядит так:
const {name: {first, last}} = person;
first // "Peter"
Имена переменных должны точно повторят имена ключей объекта.
Если есть необходимость переименовать переменные, это тоже можно сделать:
const {name: {first: firstName, last: lastName}} = person;
firstName // "Peter"
Деструктуризация позволяет указать значения по умолчанию
const {firstName, age, role = "user"} = person;
role // "user"
Одно из самых востребованных применений деструктуризации: деструктуризация аргументов функции.
function connect({
user = "guest",
host = "localhost",
port = 1234
}) {
console.log(user, host, port)
}
connect({}); // guest localhost 1234
connect({user: "admin"}); // admin localhost 1234
Но если вызвать функцию без аргументов, будет ошибка. Впрочем, её можно обойти, указав в параметрах функции аргументом по умолчанию пустой объект
function connect({
user = "guest",
host = "localhost",
port = 1234
} = {}) {
console.log(user, host, port)
}
connect(); // guest localhost 1234
Rest-элементы при деструктуризации функций позволяют собрать в отдельный объект те элементы, которым не были присвоены переменные.
const dict = {
duck: "quack",
dog: "woff",
mouse: "squeak"
}
const {duck, ...other} = dict;
duck // "quack";
other // {dog: "woff", mouse: "squeak"}
Правила использования rest-элементов такие же, как и rest-параметров.
Rest-элемент должен быть последним в списке и только один.
Ещё один новый и удобный метод Object.entries(obj);
Метод превоащает объект в двумерный массив, в котором каждый вложеный массив имеет вид [key, value].
Деструктуризация массивов
Получим первое и второе значения массива arr
var arr = [1, 2, 3, 4, 5];
var [a, b] = arr;
a // 1
b // 2
Получим второе и четвёртое значения
var arr = [1, 2, 3, 4, 5];
var [, b, , c] = arr;
c // 4
Предположим. массив многоуровневый. Вот такой
var arr = [[1, 2], [3, 4, 5]];
Не проблема. Выведем средний элемент второго вложенного массива:
var [[], [, c]] = arr;
Значения по умолчанию работают, rest-элементы тоже работают.
Шаблонные строки
Соединяют переменные и текст. переменные в фигурных скобках с знаком $ перед ними, вся строка в косых кавычках
var name = "Ann";
`I love ${name}` // "I love Ann"
В фигурных скобках может быть не только переменная, но и любое js-выражение или результат вызова функции, а строка в косых кавычках может быть как одно- так и многострочной.
Объекты
Если имена ключа и свойства совпадают, запись объекта можно сократить.
Было
var obj = {
x: x,
y: y
}
Стало:
var obj = {x, y}
Для обозначения функции - метода объекта не требуется ключ и слово function
Было
var obj {
data: function() {
// code
}
}
var obj {
data() {
// code
}
}
Появилась функция, позволяющая объединить два объекта
Object.assign(target, sources)
Здесь
target - целевой объект. в него записываются и перезаписываются свойства
sources - источник (источники), свойства которого имеют более высокий приоритет.
Если одно и то же свойство, но с разными значениями, есть и в target, и в sources, в целевой объект присвоится свойство sources.
Если мы хотим создать новый объект, а не перезаписывать target, синтаксис будет выглядеть так
Object.assign({}, target, sources)
Теперь в пустой объект записываются свойства target, а затем их дополняют и перезаписывают свойства sources.
То есть Object.assign возвращает первый аргумент, в который записаны свойства всех следующих аргументов в порядке увеличения приоритета. То есть наиболее важным будет свойство последнего аргумента, сколько бы их ни было, оно и запишется в результат.
Object.assign удобно использовать для копирования объектов.
Object.assign({}, sources)
Spread-оператор для объектов
Появился в 2018 году. работает аналогично Object.assign и позволяет объединить два объекта.
Было:
var res = Object.assign({}, target, sources);
Стало
var res = {...target, ...sources};
...
Источник
Юрий Бура. React + Redux - Профессиональная Разработка Ч.02.
https://www.udemy.com/pro-react-redux/
Дополнительная информация
Плейлист. Основы ES 6
https://www.youtube.com/playlist?list=PLqHlAwsJRxAOpWPtj2T6HhSzX-lKmKV2q