[Перевод] Современный Javascript: всё, что вы пропустили за последние 10 лет
Содержание
- Array functions
- const/let
- Nullish coalescing? and Optional chaining?… operators
- Async/Await
- Arrow functions ()=>{}
- for…of
- for await…of
- Classes
- get/set
- function default parameters
- function named parameters
- function rest… parameter
- Destructuring
- Shorthand functions aka Methods
- Promise.all
- Template literals
- Proxy
- Module import/export
- Читать ещё
(Исправления по качеству перевода, пожалуйста, присылайте в личку)
Array functions
Ознакомьтесь со всеми этими новыми нативными функциями массива. Больше нет необходимости в underscore или lodash.
Array.every ()
Array.filter ()
Array.find ()
Array.findIndex ()
Array.forEach ()
Array.from ()
Array.includes ()
Array.isArray ()
Array.lastIndexOf ()
Array.map ()
Array.reduce ()
Array.reduceRight ()
Array.some ()
Array docs
const/let
Эти новые ключевые слова объявляют переменные в области видимости блока (в отличие от глобальной или функциональной области). Использование
const
подразумевает, что значение что значение не должно изменятся, а let
дает эту возможность. Let documentation
? и ?.
??
проверяет, является ли значение нулевым или неопределенным. Больше не нужно использовать !!
.?.
проверяет истинность значения перед вызовом следующего свойства или функции. Чрезвычайно полезно при работе с дополнительными реквизитами.
Optional chaining documentation
let a, b=1
let result = a ?? b
print(result)
result = (a !== null && a !== undefined) ? a : b;
print(result)
print({x:1}?.a?.b ?? "not found")
Async/Await
Ключевые слова async/await нужны, чтобы спасти вас от ада обратных вызовов. Используйте
await
, чтобы сделать асинхронный вызов похожим на синхронный вызов, т.е. выполнение await fetchUserName()
не перейдет к следующей строке, пока fetchUserName () не будет завершен. Обратите внимание: чтобы использовать await
, вы должны выполнять функцию, объявленную как async, т.е. async function fn () {await fetchUserName ()}.
Async/Await docs.
function fetchUserName() {
return new Promise(resolve => setTimeout(resolve, 500))
}
async function withAsync() {
print("withAsync: fetching...")
await fetchUserName()
print("withAsync: done")
}
await withAsync()
function withoutAsync() {
print("withoutAsync: fetching...")
fetchUserName().then(()=>print("withoutAsync done"))
}
withoutAsync()
Arrow functions ()=>{}
Это функции, привязанные к текущему контексту. Есть три основных вида, которые вы увидите в дикой природе:
один аргумент, одна строка, много строк.
Форма с одним аргументом не требует скобок, а форма с одной строкой не требует оператора return
; возврат безоговорочный.
1 const fn = a => a*2
Один аргумент. Одна линия.
Многострочная форма требует оператора return
, если функция намеревается что-то вернуть. Для нескольких аргументов требуются круглые скобки.
const fn = (a,b) => {
console.log(a,b)
return a*b
}
Несколько аргументов, несколько строк.
Arrow function docs
for…of
Используется для перебора итератора. Аналогично
for...in
, за исключением того, что вам не нужно проверять hasOwnProperty
. Вы не можете использовать этот синтаксис цикла для объекта напрямую, потому что у объекта нет итератора. Вместо этого используйте Object.entries ({})
для получения итерации.for…of docs
const x = {a: 1, b: 2}
for (const [key, value] of Object.entries(x)) {
print(`${key}=${value}`)
}
for await…of
Асинхронная итерация была представлена в 2018 году. Как и
Promise.all
, ее можно использовать для синхронизации многих асинхронных задач. В приведенном ниже примере показаны 3 задачи, выполняющиеся асинхронно. Цикл обрабатывает один результат за раз по порядку; в этом случае самые быстрые задачи для выполнения очевидны только в конце итерации.for await…of docs
const delay = (n) => {
return new Promise((resolve) => {
setTimeout(()=>{
print("resolve "+n)
resolve(n)
}, n)
})
}
const delays = [
delay(150),
delay(50),
delay(25)
]
for await (const ret of delays) {
print("for loop await "+ret)
}
Classes
В 2015 году ES6 перенес классы в Javascript. Классы Javascript похожи на классы из других языков, которые вы знаете и любите. Наследование, методы класса, геттеры и сеттеры, свойства и т.д.
Class documentation
class A {
constructor(name) {
this.name = name
}
myProp = "myProp"
static foo() {
print("Static method says foo")
}
}
class B extends A {
constructor(name, age) {
super(name)
this.age = age
}
toString() {
return `${this.name} ${this.age}`
}
}
A.foo()
const b = new B("Catch", 22)
print(b)
print(b.myProp)
get/set
Get и set — это функции, которые называются свойствами, например
person.age = 16; person.age> 18
. Это очень удобно, когда вам нужно динамическое или вычисляемое свойство. И их можно использовать как с классами, так и с обычными объектами.get/set documentation
Classes with getters and setters
class A {
constructor() {
this._firstName = "Jane"
this._lastName = "Smith"
}
get fullName() {
return `${this._firstName} ${this._lastName}`
}
set firstName(v) {
this._firstName = v
}
}
const a = new A()
print(a.fullName)
a.firstName = "John"
print(a.fullName)
Objects with getters and setters
const x = {
get now() { return new Date() }
}
print(x.now)
function default parameters
Ура! Теперь вы можете указать параметры по умолчанию в определении вашей функции. Работает, как и следовало ожидать.
Default parameter docs
function greet(msg="Hello world") {
print(msg)
}
greet()
greet("hi")
function named parameters
С помощью магии деструктуризации объектов функции теперь могут иметь именованные параметры.
Named parameter docs
function greet({name = "Jane", age = 42} = {}){
print(name + " " +age)
}
greet()
greet({name: "John", age: 21})
function rest… parameter
Параметр сброса позволяет функции принимать произвольное количество аргументов в виде массива. Рекомендуется использовать это вместо
arguments
.Rest parameter docs
function greet(msg1, ...msgs) {
print(msg1)
msgs.forEach(s => print(s))
}
greet("hi", "hello", "world")
Object.assign and spread operator
Object.assign(target, source)
объединяет два или более объекта в один. Он изменяет целевой объект на месте, поэтому, если вы предпочитаете создать новый объект, передайте пустой литерал объекта в качестве первого аргумента.В качестве альтернативы вы можете использовать spread оператор ...
для объединения нескольких объектов: {... obj1, ... obj2}
, хотя имейте в виду, что spread
не будет вызывать сеттеры для объекта, поэтому, чтобы быть наиболее переносимым, рассмотрите Object.assign
. Spread оператор также можно использовать с массивами, как показано в последнем примере кода.
Spread syntax docs
const source = {x: 1, y: 4}
const target = Object.assign({}, source)
print(JSON.stringify(target))
const spread = {a: 1, b: 2, ...source}
print(JSON.stringify(spread))
const ary1 = [1]
const ary = [...ary1, [2,3]]
print(ary)
Destructuring
Деструктуризация позволяет извлекать значения из объектов и массивов с помощью шаблонов. Это сложная тема с множеством приложений… слишком много, чтобы я мог перечислить, но я показал некоторые из наиболее распространенных применений, которые я могу придумать.
Destructuring docs и MDN docs
function f() {
return [1, 2];
}
let [a, b] = f()
print("a="+a + " b=" + b)
const obj = {state: {id: 1, is_verified: false}}
const {id, is_verified: verified} = obj.state
print("id = " + id)
print("verified = " + verified)
for (const [key, value] of Object.entries({a: 1, b: 2, c: 3})) {
print(key + " is " + value);
}
Shorthand functions aka Methods
Функции, объявленные для объектов, могут использовать новый сокращенный стиль, в котором отсутствует ключевое слово function.
Две функции (fn1, fn2) эквивалентны в примере ниже.
Method guide
const x = {
type: "x",
shorthand() {
print("shorthand "+this.type)
},
long: function() {
print("long "+this.type)
}
}
x.shorthand()
x.long()
Promise.all
Я в основном пропускал promises, потому что async/await предпочтительнее, но иногда вам нужно синхронизировать несколько асинхронных вызовов, и Promise.all — самый простой способ сделать это.
Promise.all documentation
const delay = (n) => {
return new Promise((resolve) => {
setTimeout(()=> resolve(n), n)
})
}
async function main() {
const delays = [100, 200, 300].map(n => delay(n))
print("waiting…")
const res = await Promise.all(delays)
print("done. result is " + res)
}
main()
Template literals
Этот новый синтаксис, также известный как template strings, обеспечивает простую интерполяцию строк и «многострочные строки» (multi-line strings).
Template literal docs
let x = `multi
line
string`
print(x)
x = `1+1=${1+1}`
print(x)
Proxy
Прокси-сервер позволяет вам перехватывать вызовы get/set другого объекта. Это может быть полезно для отслеживания изменений свойства, последующего обновления DOM или создания инновационных API, таких как прокси www ниже.
Proxy docs
let _nums = [1,2,3]
let nums = new Proxy(_nums, {
set(target, key, value) {
target[key] = value
print("set called with " + key + "=" + value)
print("update DOM")
return true
}
})
nums.push(4)
print("nums: " + nums)
print("_nums: " + _nums)
Module import/export
Модули позволяют вам создавать пространство имен для вашего кода и разбивать функциональные возможности на файлы меньшего размера. В приведенном ниже примере у нас есть модуль с именем greet.js, который включается в index.html. Обратите внимание: загрузка модуля всегда откладывается, поэтому он не блокирует рендеринг HTML. Есть много способов импортировать / экспортировать функциональность из файлов js, подробнее читайте в документации по экспорту.
Import docs
function greet(msg) {
console.log("greet:", msg)
}
export default greet
Файл с именем «greet.js» в каталоге »/js».
index.html
Читать ещё
Итак, я не рассказал обо всем, что изменилось за последнее десятилетие, а только о том, что считаю наиболее полезными. Ознакомьтесь с этими другими темами.
References
Guides