Возможности JS, о которых вы возможно не знали

Сгенерированно с помощью AI Kandinsky 3.0

Сгенерированно с помощью AI Kandinsky 3.0

Всем привет! Меня зовут Леша, я фронтенд-разработчик. Крашу кнопочки, пишу js скрипты, веду канал в TG https://t.me/frontend_tales (подписывайтесь, стараюсь выкладывать полезный материал).

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

1. Разделитель числа

В числах можно использовать _ которое помогает улучшить читаемость чисел в коде.

const sixBillion = 6000000000

// Очень трудно читать
const sixBillion2 = 6000_000_000

// Читать намного легче
console.log(sixBillion2) // 6000000000

// В вычислениях тоже можно использовать
const sum = 1000 + 6000_000_000 // 6000001000

2. Оператор ? для упрощения && и тернарных операторов 

Например, у нас есть код, который мы хотим упростить:  

const obj = null
console.log(obj && obj.name)
const title1 = document.querySelector('.title')
const title = title1 ? title.innerText : undefined

Перепишем код с использованием оператора ?:

const obj = null 
console.log(obj?.name) 
const title1 = document.querySelector('.title') 
const title = title1?.innerText

3. BigInt для решения задач по вычислению больших целых чисел 

К сожалению, корректность вычисления чисел в JS, превышающих Number.MAX_SAFE_INTEGER (9007199254740991), не гарантирована, это очень грустно. 

Например:

Math.pow(2, 53) === Math.pow(2, 53) + 1 // true

// Math.pow(2, 53) => 9007199254740992

// Math.pow(2, 53) + 1 => 9007199254740992

Для вычисления больших чисел советую использовать BigInt. Это позволит избежать вычислительных ошибок. 

BigInt(Math.pow(2, 53)) === BigInt(Math.pow(2, 53)) + BigInt(1) // false

4. Чем можно заменить оператор in 

Чтобы узнать, существует ли свойство у объекта, обычно мы используем оператор in, но можно еще использовать obj.hasOwnProperty().

Оба они имеют свои недостатки:

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

  • Метод obj.hasOwnProperty() проверяет наличие свойства только в самом объекте, и не учитывает свойства, унаследованные от прототипа. Однако, этот метод не работает корректно, если объект переопределяет метод hasOwnProperty. В таком случае, вызов obj.hasOwnProperty() может привести к ошибке или неправильному результату. 

  • Оба подхода не учитывают свойства, которые могут быть доступны через цепочку прототипов. Если вам нужно проверить наличие свойства в объекте, включая его прототипы, вам придется использовать другие методы, такие как Object.getPrototypeOf() или Object.prototype.isPrototypeOf()

  • Использование in и obj.hasOwnProperty() может быть неудобным и неэффективным при работе с большими объектами или вложенными структурами данных. Это может привести к необходимости выполнять множество проверок и вызовов методов, что может замедлить выполнение программы. 

Небольшие примеры:

// Оператор in

const obj = { name: 'John', age: 25 };
console.log('name' in obj); // true
console.log('gender' in obj); // false

// Проверка наличия свойства в прототипе объекта
console.log('toString' in obj); // true

// Метод obj.hasOwnProperty()
const obj = { name: 'John', age: 25 };
console.log(obj.hasOwnProperty('name')); // true
console.log(obj.hasOwnProperty('gender')); // false

// Проверка наличия свойства в прототипе объекта
console.log(obj.hasOwnProperty('toString')); // false

Есть еще один оператор Object.hasOwn(). Он удобнее и безопаснее, чем метод obj.hasOwnProperty().

const object1 = {
  prop: 'exists',
};

console.log(Object.hasOwn(object1, 'prop'));
// Expected output: true

console.log(Object.hasOwn(object1, 'toString'));
// Expected output: false

console.log(Object.hasOwn(object1, 'undeclaredPropertyValue'));
// Expected output: false

5. # для объявления частных свойств  

Раньше для того чтобы показать что поле приватное мы добавляли _ , но теперь можно использовать #:

class Person {
  #money=1
  
  constructor (name) {
    this.name = name
  }

  get money () {
    return this.#money
  }

  set money (money) {
    this.#money = money
  }

  showMoney () {
    console.log(this.#money)
  }

}

const p1 = new Person('fatfish')
console.log(p1.money) // 1

// p1.#money = 2 // Таким способом нельзя изменить #money

p1.money = 2

console.log(p1.money) // 2
console.log(p1.#money)

6. ? вместо || 

Используйте ?? вместо ||, чтобы определить, является ли значение в левой части оператора null или undefined, а затем вернуть значение в правой части. 

const name = '';

const defaultName = 'John';
const result = name ?? defaultName;

console.log(result); // ''

const age = 0;
const defaultAge = 25;

const result2 = age ?? defaultAge;

console.log(result2); // 0

В примере выше, оператор ?? возвращает значение переменной слева от него, если это значение не равно null или undefined

В противном случае, если значение переменной слева от ?? равно null или undefined, оператор возвращает значение переменной справа от него. 

7. Преобразование String в Number 

Многие почему-то используют для преобразования string в number функцию parseInt(), когда можно использовать только оператор +

const num = parseInt("1000");

// и

const num = +"1000";

8. Сокращенный вариант для Math.floor при округлении чисел

Вместо функции Math.floor() для округления числа можно использовать оператор ~~:

Math.floor(5.25) // 5.0

// или

~~5.25 // 5.0

9. Преобразование значения в Boolean 

Для преобразования любого значения в Boolean нужно использовать двойной восклицательный знак!:

!!true    // true
!!2       // true
!![]      // true
!!"Test"  // true

!!false   // false
!!0       // false
!!""      // false

10. Объединение массивов 

Для объединения массивов хорошо использовать spread (…) оператор, вместо метода concat():

const nums1 = [1, 2, 3];
const nums2 = [4, 5, 6];

let newArray = nums1.concat(nums2);

// spread 
newArray = [...nums1, ...nums2];

// можно добавлять значения в массив
numbers = [...numbers, 4, 5];

11. Удаление повторяющихся элементов из массива 

Удаляем через Set() — множество:

const numbers = [1, 1, 20, 3, 3, 3, 9, 9];

const uniqueNumbers = [...new Set(numbers)]; // [1, 20, 3, 9]

12. Изменение мест двух переменных без использования третьей

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

let x = 1;
let y = 2;
let temp = x;

x = y;
y = temp;

[x, y] = [y, x];

13. document.designMode 

Связанный с интерфейсным JavaScript,  designMode позволяет редактировать любой контент на странице. Просто откройте консоль браузера и введите следующее:  

document.designMode = 'on';

Обязательно попробуйте, очень классная штука) 

14. Быстрое преобразование Float в Integer 

Если вы хотите преобразовать число с плавающей точкой в целое число, вы можете использовать Math.floor(), Math.ceil() или Math.round().

Но есть также более быстрый способ обрезать число с плавающей точкой до целого числа, используя | оператор побитового ИЛИ.

console.log(23.9 | 0);  // 23
console.log(-23.9 | 0); // -23

15. Обрезание массива

Если вы хотите удалить значения из конца массива деструктивно, есть более быстрые альтернативы, чем использование splice()

Пример:

let array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
array.length = 4;

console.log(array); // [0, 1, 2, 3]

Кстати, часто на собесах спрашивают, что будет если мы свойству length присвоим значение.

16. Получить n последних элементов массива 

Метод массива slice() может принимать отрицательные целые числа, и при наличии он будет принимать значения с конца массива, а не с начала. 

let array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

console.log(array.slice(-1)); // [9]
console.log(array.slice(-2)); // [8, 9]
console.log(array.slice(-3)); // [7, 8, 9]

© Habrahabr.ru