Сегодня, в девятой части перевода руководства по JavaScript, будет сделан обзор возможностей, которые появились в языке благодаря стандартам ES7, ES8 и ES9.
> Часть 1: первая программа, особенности языка, стандарты
> Часть 2: стиль кода и структура программ
> Часть 3: переменные, типы данных, выражения, объекты
> Часть 4: функции
> Часть 5: массивы и циклы
> Часть 6: исключения, точка с запятой, шаблонные литералы
> Часть 7: строгий режим, ключевое слово this, события, модули, математические вычисления
> Часть 8: обзор возможностей стандарта ES6
> Часть 9: обзор возможностей стандартов ES7, ES8 и ES9
Array.prototype.includes()
.Array.prototype.includes()
предназначен для проверки наличия в массиве некоего элемента. Находя в массиве искомое, он возвращает true
, не находя — false
. До ES7 для выполнения той же операции служил метод indexOf()
, который возвращает, в случае нахождения элемента, первый индекс, по которому его можно обнаружить в массиве. Если же indexOf()
элемента не находит — он возвращает число -1
.-1
преобразуется в true
. Как результат, для проверки результатов работы indexOf()
следовало пользоваться не особенно удобной конструкцией следующего вида.if ([1,2].indexOf(3) === -1) {
console.log('Not found')
}
indexOf()
, не находя элемента, возвращает false
, воспользоваться чем-то вроде показанного ниже, код будет работать неправильно.if (![1,2].indexOf(3)) { //неправильно
console.log('Not found')
}
![1,2].indexOf(3)
даёт false
.includes()
подобные сравнения выглядят гораздо логичнее.if (![1,2].includes(3)) {
console.log('Not found')
}
[1,2].includes(3)
возвращает false
, это значение оператор !
превращает в true
и в консоль попадает сообщение о том, что искомый элемент в массиве не найден.Math.pow()
, но пользоваться им удобнее, чем библиотечной функцией, так как он является частью языка.Math.pow(4, 2) == 4 ** 2 //true
Object.values()
.Object.entries()
.Object.getOwnPropertyDescriptors()
.String
— padStart()
и padEnd()
.padStart()
заполняет текущую строку другой строкой до тех пор, пока итоговая строка не достигнет нужной длины. Заполнение происходит в начале строки (слева). Вот как пользоваться этим методом.str.padStart(targetLength [, padString])
str
— это текущая строка, targetLength
— длина итоговой строки (если она меньше длины текущей строки — эта строка будет возвращена без изменений), padString
— необязательный параметр — строка, используемая для заполнения текущей строки. Если параметр padString
не задан — для дополнения текущей строки до заданной длины используется символ пробела.padEnd()
аналогичен padStart()
, но заполнение строки происходит справа.const str = 'test'.padStart(10)
const str1 = 'test'.padEnd(10,'*')
console.log(`'${str}'`) //' test'
console.log(`'${str1}'`) //'test******'
padStart()
с указанием лишь желаемой длины итоговой строки, в начало исходной строки были добавлены пробелы. При использовании padEnd()
с указанием длины итоговой строки и строки для её заполнения в конец исходной строки были добавлены символы *
.const person = { name: 'Fred', age: 87 }
const personValues = Object.values(person)
console.log(personValues) // ['Fred', 87]
[key, value]
, ключи и значения собственных свойств объекта.const person = { name: 'Fred', age: 87 }
const personValues = Object.entries(person)
console.log(personValues) // [['name', 'Fred'], ['age', 87]]
value
— значение свойства объекта.writable
— содержит true
если свойство можно менять.get
— содержит функцию-геттер, связанную со свойством, или, если такой функции нет — undefined
.set
— содержит функцию-сеттер для свойства или undefined
.configurable
— если тут будет false
— свойство нельзя удалять, нельзя менять его атрибуты за исключением значения.enumerable
— если в этом свойстве будет содержаться true — свойство
является перечислимым.Object.getOwnPropertyDescriptors(obj)
const person = { name: 'Fred', age: 87 }
const propDescr = Object.getOwnPropertyDescriptors(person)
console.log(propDescr)
/*
{ name:
{ value: 'Fred',
writable: true,
enumerable: true,
configurable: true },
age:
{ value: 87,
writable: true,
enumerable: true,
configurable: true } }
*/
Object.assign()
, который появился в стандарте ES6.console.log()
то, что пытаются записать в его соответствующее свойство.const person1 = {
set name(newName) {
console.log(newName)
}
}
person1.name = 'x' // x
assign()
.const person2 = {}
Object.assign(person2, person1)
person2.name = 'x' // в консоль ничего не попадает, сеттер не скопирован
name
, которое в исходном объекте было сеттером, теперь представлено в виде обычного свойства.Object.defineProperties()
(он появился в ES5.1) и Object.getOwnPropertyDescriptors()
.const person3 = {}
Object.defineProperties(person3,
Object.getOwnPropertyDescriptors(person1))
person3.name = 'x' //x
Object.assign()
, свойственны и для метода Object.create()
при использовании его для клонирования объектов.const doSomething = (
var1,
var2,
) => {
//...
}
doSomething(
'test1',
'test2',
)
async/await
, которую можно считать важнейшим новшеством этой версии языка.async/await
решает проблему промисов и повышает удобство работы с асинхронным кодом.function doSomethingAsync() {
return new Promise((resolve) => {
setTimeout(() => resolve('I did something'), 3000)
})
}
async function doSomething() {
console.log(await doSomethingAsync())
}
console.log('Before')
doSomething()
console.log('After')
Before
After
I did something
doSomething()
программа продолжает выполняться, после Before
в консоль тут же выводится After
, а после того, как пройдут три секунды, выводится I did something
.function promiseToDoSomething() {
return new Promise((resolve)=>{
setTimeout(() => resolve('I did something'), 10000)
})
}
async function watchOverSomeoneDoingSomething() {
const something = await promiseToDoSomething()
return something + ' and I watched'
}
async function watchOverSomeoneWatchingSomeoneDoingSomething() {
const something = await watchOverSomeoneDoingSomething()
return something + ' and I watched as well'
}
watchOverSomeoneWatchingSomeoneDoingSomething().then((res) => {
console.log(res) // I did something and I watched and I watched as well
})
Promise.prototype.finally()
.first
и second
, а все остальные — в константу others
.const numbers = [1, 2, 3, 4, 5]
const [first, second, ...others] = numbers
console.log(first) //1
console.log(second) //2
console.log(others) //[ 3, 4, 5 ]
spread
позволяет передавать массивы в функции, ожидающие обычные списки параметров.const numbers = [1, 2, 3, 4, 5]
const sum = (a, b, c, d, e) => a + b + c + d + e
const res = sum(...numbers)
console.log(res) //15
const { first, second, ...others } =
{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
console.log(first) //1
console.log(second) //2
console.log(others) //{ third: 3, fourth: 4, fifth: 5 }
const items = { first, second, ...others }
console.log(items) //{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
for-await-of
позволяет вызывать асинхронные функции, возвращающие промисы, в циклах. Такие циклы ожидают разрешения промиса перед переходом к следующему шагу. Вот как это выглядит.for await (const line of readLines(filePath)) {
console.log(line)
}
async/await
.then()
. Если что-то идёт не так — вызывается метод catch()
. Метод finally()
позволяет выполнять некий код независимо от того, что происходило до этого.fetch('file.json')
.then(data => data.json())
.catch(error => console.error(error))
.finally(() => console.log('finished'))
?<=
). Это позволяет искать в строках некие конструкции, перед которыми есть какие-то другие конструкции.?=
, имелась в регулярных выражениях, реализованных в JavaScript, и до стандарта ES2018. Такие проверки позволяют узнать, следует ли за неким фрагментом строки другой фрагмент.const r = /Roger(?= Waters)/
const res1 = r.test('Roger is my dog')
const res2 = r.test('Roger is my dog and Roger Waters is a famous musician')
console.log(res1) //false
console.log(res2) //true
?!
выполняет обратную операцию — совпадение будет найдено только в том случае, если за заданной строкой не идёт другая строка.const r = /Roger(?! Waters)/g
const res1 = r.test('Roger is my dog')
const res2 = r.test('Roger is my dog and Roger Waters is a famous musician')
console.log(res1) //true
console.log(res2) //false
?<=
.const r = /(?<=Roger) Waters/
const res1 = r.test('Pink Waters is my dog')
const res2 = r.test('Roger is my dog and Roger Waters is a famous musician')
console.log(res1) //false
console.log(res2) //true
?<!
.const r = /(?<!Roger) Waters/
const res1 = r.test('Pink Waters is my dog')
const res2 = r.test('Roger is my dog and Roger Waters is a famous musician')
console.log(res1) //true
console.log(res2) //false
\d
, соответствующий любой цифре, класс \s
, соответствующий любому пробельному символу, класс \w
, который соответствует любому буквенно-цифровому символу, и так далее. Возможность, о которой идёт речь, расширяет набор классов, которыми можно пользоваться в регулярных выражениях, позволяя работать с Unicode-последовательностями. Речь идёт о классе \p{}
и об обратном ему классе \P{}
.\p{}
. Так, например, свойство Script
определяет семейство языков, к которому принадлежит символ, свойство ASCII
, логическое, принимает значение true
для ASCII-символов, и так далее. Например, выясним, содержат ли некие строки исключительно ASCII-символы.console.log(r.test('abc')) //true
console.log(r.test('ABC@')) //true
console.log(r.test('ABCЖ')) //false
ASCII_Hex_Digit
принимает значение true
только для символов, которые можно использовать для записи шестнадцатеричных чисел.const r = /^\p{ASCII_Hex_Digit}+$/u
console.log(r.test('0123456789ABCDEF')) //true
console.log(r.test('H')) //false
Uppercase
, Lowercase
, White_Space
, Alphabetic
, Emoji
.Script
определить, какой алфавит используется в строке. Здесь мы проверяем строку на использование греческого алфавита.const r = /^\p{Script=Greek}+$/u
console.log(r.test('????????')) //true
console.log(r.test('hey')) //false
const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
const result = re.exec('2015-01-02')
console.log(result)
/*
[ '2015-01-02',
'2015',
'01',
'02',
index: 0,
input: '2015-01-02',
groups: { year: '2015', month: '01', day: '02' } ]
*/
const re = /(\d{4})-(\d{2})-(\d{2})/
const result = re.exec('2015-01-02')
console.log(result)
/*
[ '2015-01-02',
'2015',
'01',
'02',
index: 0,
input: '2015-01-02',
groups: undefined ]
*/
s
приводит к тому, что символ .
(точка) будет, кроме прочих, соответствовать и символу новой строки. Без использования этого флага точка соответствует любому символу за исключением символа новой строки.console.log(/hi.welcome/.test('hi\nwelcome')) // false
console.log(/hi.welcome/s.test('hi\nwelcome')) // true
К сожалению, не доступен сервер mySQL