DevGang
Авторизоваться

6 передовых функций JavaScript, которые вы можете использовать сегодня 

Быть программистом на JavaScript - прекрасное время. Веб-технологии развиваются все более быстрыми темпами, и поставщики браузеров больше не стесняются сразу же внедрять новые и инновационные функции. Этот сдвиг в развитии означает, что программистам необходимо постоянно обновлять свой набор навыков, чтобы оставаться конкурентоспособными на своей должности.

В этой статье мы рассмотрим шесть функций ES2020 и ES2021, которые недавно были реализованы в современных браузерах, и увидим, как они помогают разработчикам JavaScript писать менее подверженный ошибкам и более эффективный код.

BigInt

При работе с большими целыми числами в JavaScript нам часто приходится использовать сторонние библиотеки, потому что тип Number не может безопасно представлять целочисленные значения больше 253.

Рассмотрим следующий пример:

console.log(9999999999999999);    // => 10000000000000000

В этом коде 9999999999999999 округляется до 10000000000000000, поскольку оно больше наибольшего целого числа, поддерживаемого типом Number. Если вы не будете осторожны, такое округление может поставить под угрозу безопасность вашей программы.

Вот еще один пример:

// notice the last digit
9800000000000007 === 9800000000000008;    // => true

К счастью, в ECMAScript недавно был представлен тип данных BigInt, который обеспечивает простой способ представления целых чисел, превышающих поддерживаемый диапазон Number.

BigInt можно создать, добавив n к целому числу.

Сравните:

console.log(9800000000000007n);    // => 9800000000000007n
console.log(9800000000000007);     // => 9800000000000008

Также можно использовать конструктор:

BigInt('9800000000000007');    // => 9800000000000007n

Теперь вы можете выполнять арифметические операции с большими целыми числами в стандартном JavaScript без использования обходного пути:

9999999999999999 * 3;      // => 30000000000000000

// with BigInt, integer overflow won’t be an issue
9999999999999999n * 3n;    // => 29999999999999997n

Важно понимать, что Number и BigInt два различных типа данных, и вы не можете сравнить их со строгим оператор равенства:

5n === 5;     // => false
 
typeof 5n;    // => bigint
typeof 5;     // => number

Однако вы все равно можете использовать оператор равенства, потому что он неявно преобразует операнды в один и тот же тип перед сравнением:

5n == 5; // => true

Вы можете выполнять арифметические операции с BigInt так же, как с Number:

50n + 30n;    // => 80n
50n - 30n;    // => 20n
50n * 20n;    // => 1000n
50n / 5n;     // => 10n
56n % 10n;    // => 6n
50n ** 4n;    // => 6250000n

Операторы инкремента, декремента и унарного отрицания также работают должным образом. Но унарный оператор плюс (+) является исключением, и его применение к BigInt вызовет TypeError:

let x = 50n;
++x;    // => 51n
--x;    // => 50n
 
-50n;    // => -50n
+50n;    // => TypeError: Cannot convert a BigInt value to a number

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

ES2020 добавляет к языку JavaScript еще один оператор короткого замыкания: нулевой оператор объединения (??). Этот оператор отличается от существующих сокращающих операторов тем, что он проверяет, является ли его левый операнд нулевым (null или undefined), а не ложным.

Другими словами, ?? возвращает свой правый операнд, только если его левый операнд равен null или undefined:

null ?? 2; // => 2
undefined ?? 2; // => 2

0 ?? 2; // => 0
false ?? true; // => false

Логический оператор ИЛИ (||), с другой стороны, возвращает правый операнд, если левый один из 0, -0, 0n, false, "" (пустая строка), null, undefined или NaN. Сравните:

null ?? 2;       // => 2
undefined ?? 2;  // => 2
 
0 ?? 2;           // => 0
false ?? true;    // => false

?? особенно удобен при установке значения по умолчанию для свойства или переменной. Например:

function Config(darkMode)  {
    this.darkMode = darkMode ?? true;
    // …
}
 
new Config(null);     // => {darkMode: true}
new Config();         // => {darkMode: true}
new Config(false);    // => {darkMode: false}

Конструктор Config предоставляет значение по умолчанию для свойства darkMode в случае, если данное значение nullish или значения не задано.

?? также полезно при работе с DOM API:

// querySelector() returns null when the element doesn’t exist in the document
const elem = document.querySelector('elem') ?? document.createElement('elem');

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

Круглые скобки также помогают читабельности кода:

false || (true ?? true);   // no error
false || true ?? true;     // => SyntaxError

Promise.any()

ES2015 представил объект обещания с двумя методами: Promise.all() и Promise.race(). ES2021 дополнительно расширяет асинхронные возможности JavaScript, добавляя Promise.any(). Этот новый метод возвращает обещание, которое выполняется, когда выполняется одно из обещаний в данной итерации, или отклоняет, если все обещания отклоняются.

Вот как это работает:

const promise = Promise.any([
    Promise.reject('Error'),
    fetch('https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png', {mode: 'no-cors'}).then(() => 'google.com'),
    fetch('https://en.wikipedia.org/static/images/project-logos/enwiki.png', {mode: 'no-cors'}).then(() => 'wikipedia.org'),
    fetch('https://s.w.org/images/home/swag_col-1.jpg?1', {mode: 'no-cors'}).then(() => 'w.org')
]);
 
promise.then((fastest) => {
    // the first promise that fulfills
    console.log(fastest);
}).catch((error) => {
    console.log(error);
});

Этот код выполняет три запроса на выборку. Как только одно из обещаний исполняется, оно возвращает обещание, которое исполняется с ценностью от этого обещания. Promise.any() отличается от Promise.race() тем, как он обрабатывает отказ. Обещание, возвращаемое Promise.any() отклоняется только в том случае, если все обещания в отклонены:

const promise = Promise.any([
    Promise.reject('Exception1'),
    Promise.reject('Exception2'),
    Promise.reject('Exception3')
]);
 
promise.then((response) => {
    // ...
}).catch((e) => {
    console.log(e.errors);
});
 
// logs:
// => ["Exception1", "Exception2", "Exception3"]

Обратите внимание, как значение отклонения всех обещаний передается в виде массива методу catch(). Кроме того, вы можете использовать async и await для обработки результата:

(async () => {
    try {
        result = await Promise.any([
            Promise.reject('Exception1'),
            Promise.reject('Exception2'),
            Promise.resolve('Success!')
        ]);
 
        console.log(result);
    } catch(e) {
        console.log(e);
    }
})();
 
// logs:
// => Success!

Promise.allSettled()

Еще один полезный метод, который недавно был добавлен - это Promise.allSettled(). Этот метод, который дополняет существующий Promise.all(), предназначен для возврата результата всех обещаний - как отклоненных, так и выполненных.

Вот пример:

const p1 = Promise.resolve('Success');
const p2 = Promise.reject('Exception');
const p3 = Promise.resolve(123);
 
Promise.allSettled([p1, p2, p3]).then((response) => {
    response.forEach(result => console.log(result.value || result.reason))
});

// logs:
// => Success
// => Error!
// => 123

Обратите внимание, как результат всех обещаний передается в виде массива в функцию then(). Внутри функции then() метод forEach() выполняет циклический перебор элементов массива. Если левый операнд оператора || не определен, он будет записан в консоль. В противном случае обещание было отклонено, и правильный операнд будет записан в журнал.

Для сравнения: Promise.all() немедленно бросает reject, как только одно из обещаний отклоняется.

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

Необязательный оператор цепочки (?.) позволяет получить доступ к вложенному свойству без проверки каждого свойства в цепочке.

Рассмотрим следующий пример:

const obj = {};
const nickname = obj?.user?.profile?.nickname;
 
console.log(nickname);    // => undefined

Этот код пытается присвоить значение вложенного свойства константе. Но такого свойства нет в obj. К тому же user и profile не существует. Но благодаря необязательному оператору связывания код возвращается undefined, а не выдает ошибку.

С обычным оператором цепочки вы получите ошибку:

const obj = {};
const nickname = obj.user.profile.nickname;
 
console.log(nickname);    // => TypeError

Необязательный оператор цепочки также можно использовать при вызове метода объекта:

const obj = {};
const value = obj.myMethod?.();
 
console.log(value);    // => undefined

Здесь myMethod не существует в obj; однако, поскольку он вызывается с использованием необязательного оператора цепочки, возвращаемое значение - undefined. Опять же, с обычным оператором цепочки вы получите ошибку.

Но что, если вы хотите получить доступ к свойству динамически? Маркер ?.[] позволяет ссылаться на переменную с помощью квадратных скобок.

Вот как это работает:

const obj = {
    user: {
      id: 123
    }
};
 
const prop = 'nickname';
const nickname = obj?.user?.profile?.[prop];
 
console.log(nickname);    // => undefined

code>globalThis

Хотя JavaScript был создан с целью выполнения сложных функций в веб-браузерах, теперь он может работать в совершенно разных средах, таких как серверы, смартфоны и даже роботы. Поскольку каждая среда имеет свою собственную объектную модель, для доступа к глобальному объекту вам потребуется другой синтаксис.

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

globalThis предоставляет единое универсальное свойство во всех средах для доступа к глобальному объекту:

// browser environment
console.log(globalThis);    // => Window {...}
 
// web worker environment
console.log(globalThis);    // => DedicatedWorkerGlobalScope {...}
 
// node environment
console.log(globalThis);    // => Object [global] {...}

Раньше разработчикам приходилось писать дополнительные проверки, чтобы убедиться, что они ссылаются на правильное свойство. С globalThis, это больше не требуется, и код будет работать как в window, так и в не window контекстах. Имейте в виду, что вам все равно может потребоваться использовать полифилл для обратной совместимости в старых браузерах.

Источник:

#JavaScript
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

Поделитесь своим опытом, расскажите о новом инструменте, библиотеке или фреймворке. Для этого не обязательно становится постоянным автором.

Попробовать

Оплатив хостинг 25$ в подарок вы получите 100$ на счет

Получить