Проверенные новые функции ES11, сколько вы уже использовали?

JavaScript

Спецификация ES11 была завершена в начале этого года и ввела много новых стандартов, в этой статье мы сосредоточимся на нескольких полезных и интересных из них.

Особенности Роба Профета:

  • частная переменная
  • Promise.allSettled
  • BigInt новый тип данных
  • Нулевой оператор объединения
  • Необязательный оператор цепочки
  • Динамический импорт
  • String.prototype.matchAll Добавлено matchAll
  • globalДобавляет глобальный объект
  • Экспорт пространства имен модуля импортирует определенные пространства имен

частная переменная

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

Ниже мы возьмем простой

class Hero {
    #aggressivity = 0
    constructor (aggressivity){
      this.#aggressivity = aggressivity
    }
    getHurt(){
      return this.#aggressivity
    }
    setAggressivity(aggressivity){
      this.#aggressivity = aggressivity
    }
}

const shooter = new Hero(100)
let hurt = shooter.getHurt()
console.log(hurt) //100
console.log(shooter.#aggressivity) //Error : Uncaught SyntaxError: Private field '#aggressivity' must be declared in an enclosing class

В приведенном выше коде мы обнаружим, что к #aggressivity нельзя получить прямой доступ, и будет выдано исключение. Доступ к нему можно получить только через класс, и его можно единообразно изменить с помощью общедоступных методов единого класса.

Предположим, что стрелок в настоящее время несетжестокийНавыки, повысить10% урона, мы можем изменить силу атаки через setAggressivity!

let aggressivity = parseInt(hurt * 1.1)
shooter.setAggressivity(aggressivity)
console.log(shooter.getHurt()) // 110

Promise.allSettled

Прежде чем говорить об этой новой функции, давайте кратко рассмотримPromise.allтак же какPromise.race, предположим, почемуPromise.allSettledэта новая функция

Promise.all: Несколько экземпляров Promise могут быть заключены в новый экземпляр Promise. При этом возвращаемые значения успеха и неудачи различны, при успехе возвращает массив результатов, а при неудаче возвращает значение первого отклоненного состояния отказа.

let p1 = new Promise((resolve, reject) => {
  resolve('成功了')
})

let p2 = new Promise((resolve, reject) => {
  resolve('success')
})

let p3 = Promse.reject('失败')

Promise.all([p1, p2]).then((result) => {
  console.log(result) //['成功了', 'success']
}).catch((error) => {
  console.log(error)
})

Promise.all([p1,p3,p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error) // 失败了,打出 '失败'
})

Promise.race: возвращает промис. Как только промис инициирует разрешение или отклонение, он напрямую возвращает статус результата промиса.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
});
//输出 "two" 因为promise2返回结果比promise1快

Иногда нам может понадобиться знать все результаты для выполнения каких-то операций, и не важно, успешны результаты выполнения или нет.До того, как не будет Promise.allSettled, нам нужно реализовать его самим, что можно сделать следующим образомРеализовать Promise.allSettled

let allSettled = (funcArr) => {
  return new Promise((resolve) => {
    let sttled = 0
    let result = []
    for(let index = 0;index<funcArr.length;index++){
      const element = funcArr[index]
      element
      .then(res => { 
        result[index] = {
          status: 'fulfilled',
          value: res
        }
      })
      .catch(err => { 
        result[index] = {
          status: 'rejected',
          reason: err
        }
      })
      .finally(() => { ++sttled === funcArr.length && resolve(result) })
    }
  })
}

//使用
const promises = [
    Promise.reject('c'),
    Promise.resolve('a'),
    Promise.resolve('b'),
];

allSettled(promises).then(res => {
    console.log(res)
})

// 打印结果
// [{"status":"rejected","reason":"c"},
// {"status":"fulfilled","value":"a"},
// {"status":"fulfilled","value":"b"}]

И после выхода новой функции Promise.allSettled мы можем использовать ее напрямую, без необходимости реализовывать ее отдельно.

const promises = [
    Promise.reject('c'),
    Promise.resolve('a'),
    Promise.resolve('b'),
];
Promise.allSettled(promises).then(res =>{
 console.log(res)
})
// 打印结果
// [{"status":"rejected","reason":"c"},
// {"status":"fulfilled","value":"a"},
// {"status":"fulfilled","value":"b"}]

В возвращаемом результате будет возвращен массив, включающий все результаты успеха и неудачи.Каждый элемент массива является объектом, который содержитstatusСвойства, соответствующие выполненным и отклоненным. когда статусfulfilled, представляя успех, в том числеvalue, представляющий успешный результат когда статусrejected, что означает отказ, в том числеreason, представляя причину отказа

BigInt

Отсутствие явных целочисленных типов в JS часто сбивает с толку. Многие языки программирования поддерживают несколько числовых типов, таких как float, double, int и double, но это не относится к JS. В JS, как определено стандартом IEEE 754-2008, все числа имеют двойную точность.64-битный формат с плавающей запятойВыражать.

Очень большие целые числа, которые не могут быть представлены точно, автоматически округляются в соответствии с этим стандартом. Чтобы быть точным, тип Number в JS может безопасно представлять только целые числа между -9007199254740991 (-(2^53-1)) и 9007199254740991 (2^53-1), любое целочисленное значение за пределами этого диапазона может потерять точность.

console.log(9999999999999999);    //10000000000000000

JS предоставляетNumber.MAX_SAFE_INTEGERконстанта для представления наибольшего безопасного целого числа,Number.MIN_SAFE_INTEGERКонстанта представляет собой наименьшее безопасное целое число:

// 注意最后一位的数字
const A = Number.MAX_SAFE_INTEGER + 1
const B = Number.MAX_SAFE_INTEGER + 2

console.log(Number.MAX_SAFE_INTEGER) //9007199254740991
console.log(A) //9007199254740992
console.log(B) //9007199254740992

console.log(A === B) //true

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

BigInt родился и может выполнять арифметические операции с большими целыми числами в стандартном JS, не беспокоясь о риске потери точности.

Создание типа данных BIGINT очень прост, добавляя за целым числомnможет быть, илиСоздайте экземпляр через BigInt()

const bigint = 999999999999999999n
const bigintByMethod = BigInt('999999999999999999')
console.log(bigint) //999999999999999999n
console.log(bigintByMethod) //999999999999999999n
console.log(bigint === bigintByMethod) //true

//布尔值
console.log(BigInt(true)) //1n
console.log(BigInt(false)) //0n

console.log(typeof bigint) //"bigint" 

BigInt и Number — это два типа данных, с которыми нельзя работать и которые можно сравнивать по размеру.

console.log(88n == 88) //true
console.log(88n === 88) //false
console.log(88n+1) //Error =>Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions

Между BigInt,За исключением унарного оператора плюс (+), другие можно использовать для BigInt

console.log(1n + 2n) //3n
console.log(1n - 2n) //-1n
console.log(+ 1n) //Uncaught TypeError: Cannot convert a BigInt value to a number
console.log(- 1n) //-1n
console.log(10n * 20n) //200n
console.log(23n%10n) //3n
console.log(20n/10n) //2n
......

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

console.log(25n / 10n) //2n
console.log(29n / 10n) //2n

Последнее, на что следует обратить внимание, это то, что при преобразовании между типом Boolean и типом BigInt метод обработки такой же, как и для типа Number, до тех пор, покане 0n, BigInt считается истинным

if (5n) {
    // 这里代码块将被执行
}

if (0n) {
    // 这里代码块不会执行
}

Нулевой оператор объединения

Добавлен новый логический оператор ??, который обрабатывает null и undefined, работает как логическое или ( || ), но наоборот

|| Возвращает левое значение, если оно истинно, иначе возвращает правое

0 || 5 // return 5
"" || 5 // return 5
"前端公虾米" || 'V5' //return "前端公虾米"

?? Если null или undefined, вернуть правую сторону, в противном случае вернуть левую сторону

0 ?? 5 //return 0
"" ?? 5 //return ""
null ?? 5 // return 5
undefined ?? 5 // return 5
false ?? 5 //return false
NaN ?? 5 // return NaN

При использовании оператора ?? следует учитывать, что

  • Нельзя комбинировать с другими операторами, такими как &&, ||
  • Но если вы используете круглые скобки, чтобы обернуть его, вы можете использовать его в комбинации
"前端公虾米" || undefined ?? "Sneaker" //Uncaught SyntaxError: Unexpected token '??'
"前端公虾米" && undefined ?? "Sneaker" //Uncaught SyntaxError: Unexpected token '??'

("前端公虾米" || undefined) ?? "(๑•̀ㅂ•́)و✧" //"前端公虾米"
("前端公虾米" && null) ?? "一起学习" //"一起学习"

Необязательный оператор цепочки

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

Необязательный оператор цепочки находит первый в цепочке при поиске вложенных объектов.undefinedилиnullЯ немедленно остановлюсь и верну его.undefined, вместо того чтобы постоянно смотреть вниз и выкидывать ошибки

const obj = {
  foo: {
    bar: {
      baz: 42,
    },
  },
}
console.log(obj.fo.bar.baz) //Uncaught TypeError: Cannot read property 'bar' of undefined

在诸如此类的对象里,我们通常进行数据安全检查来访问嵌套对象,否则将抛错
if(obj&&obj.foo&&obj.foo.bar){
 console.log(obj.foo.bar.baz) // 42
}

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

console.log(obj?.foo?.bar?.baz) //42
            
console.log(obj.foo.bar?.baz) //42

Динамический импорт

В стандартном импорте импорта он импортируется статически, и все импортируемые модули компилируются при их загрузке и не могут быть скомпилированы по требованию. Когда нам нужен условный импорт, мы можем использовать толькоrequire().

Но теперь у нас есть способ исправить эту ситуацию, потому что динамический импорт может эффективно сократить компиляцию неиспользуемого кода, что может повысить скорость загрузки выше сгиба и загрузки по требованию. Итак, зачем нам динамический импорт?

  • Статический импорт требует времени загрузки, и многие модули должны быть отрисованы перед первым экраном.
  • Статический импорт потребляет много памяти при импорте
  • Могут быть некоторые модули, которые не существуют при загрузке
  • Уменьшить некоторые побочные эффекты условных зависимостей
//通用导入方式
import("/module/sneaker/test.js")
.then(module => {
 //模块相关操作
})

//await
const getModule = await import("/module/sneaker/test.js")

//通过async await
const getUserInfo = async (hasLogin) => {
 if(!hasLogin){
  const user = await import("/module/sneaker/user.js")
    user.getInfo()
 }
}

matchAll

Новый метод, основанный на прототипе String, который позволяет сопоставлять строку с регулярным выражением и возвращать итератор всех совпадений. в состоянии пройтиfor...ofтраверс илиоператор...,Array.fromПреобразовать итератор результата в массив

const string = 'Hello Sneaker,Where is the library?'
const regex = /[A-W]/g
const matches = string.matchAll(regex)

console.log(...matches)
//["H", index: 0, input: "Hello Sneaker,Where is the library?", groups: undefined] 
//["S", index: 6, input: "Hello Sneaker,Where is the library?", groups: undefined] 
//["W", index: 14, input: "Hello Sneaker,Where is the library?", groups: undefined] 

globalThis

Это обеспечивает стандартный способ доступа к глобальным объектам. В браузере мы можем использоватьwindow/self/framesдля доступа к глобальному объекту, но для веб-воркеров используйте толькоself, в Node совсем по-другому, нужно использоватьglobal.

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

const globalObj = (()=>{
 if(self) return self
  if(window) return window
  if(global) return global
  throw new Error('Sorry!No global obj found')
})
//Browser 
globalThis === window //true

//Webworker
globalThis === self //true

//Node
globalThis === global //true

Отныне реализуйте объединение глобальных объектов!

Экспорт пространства имен модуля импортирует определенные пространства имен

export * as ns from './module

//等同于
import * as ns from './module'
export {ns}

Импорт определенного пространства имен на самом деле не импортирует модуль, а просто пересылает модуль, так что модуль нельзя использовать непосредственно в этом модуле.

Ссылаться на

  • ecma-262
  • MDN

наконец

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