Друкарня від WE.UA

Шпаргалка по JavaScript Symbol-ам

Що таке Symbol в JavaScript

Symbol — один з примітивних типів даних. Це дещо своєрідне та може бути складнішим в розумінні.

Виклик `Symbol()` створює новий символ, значення якого гарантовано відрізняється від будь-яких створений раніше символів.

const sym1 = Symbol();
const sym2 = Symbol();
sym1 === sym2; // false

Що ж це за значення? Це не текст, не літера, не число. У символів немає якогось текстового представлення. Тому якщо ви спробуєте вивести символ в консоль, ви побачите лише “Symbol()” — факт того, що це символ, але не його “значення”, бо його заховано глибоко в реалізації рушія.

console.log( Symbol() ); // Symbol() 🤷‍♂️

Саме гарантія неповторюваності є ключовою механікою символів. Новостворена змінна єдиний спосіб використовувати той самий символ.

function createObj() {
  const sym = Symbol()
  const obj = {
    [sym]: 'Привіт, Світе!'
  };

  console.log( obj[sym] ) // Привіт, Світе!

  return obj;
}

const obj2 = createObj();
console.log(obj) // { Symbol(): "Привіт, Світе!" }

Вивівши структуру obj2 ви можете побачити, що в ньому є властивість за ключем-символом, але ви не можете отримати доступ до цієї властивості, оскільки змінна-ключ залишилась в області видимості createObj().

Для чого вони потрібні

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

В моїй практиці при розробці бібліотеки я кілька разів опирався на символи, щоб домішувати щось в користувацькі об’єкти та гарантувати, що я не перезапишу якісь дані.

const cachedKey = Symbol()

export function doSomeJobWithObjectAndCacheResult(obj) {
  if (obj[cachedKey] === undefined) {
    obj[cachedKey] = doSomeJobWithObject(obj)
  }

  return obj[cachedKey]
}
  1. Оскільки кожен створений символ це унікальний примітив, то функція вище гарантує, що в переданому об’єкті не може бути поля за цим символом створеним десь окрім як цією функцією.

  2. Доступ до цього поля неможливий за межами цієї функції.

Які є вбудовані Symbol

В JavaScript чимало символів створюються та використовуються замовчуванням. Всі вони визначені у статичних властивостях Symbol.

console.dir(Symbol) /*
{
  name: "Symbol"
  asyncIterator: Symbol("Symbol.asyncIterator"),
  hasInstance: Symbol("Symbol.hasInstance"),
  isConcatSpreadable: Symbol("Symbol.isConcatSpreadable"),
  iterator: Symbol("Symbol.iterator"),
  match: Symbol("Symbol.match"),
  matchAll: Symbol("Symbol.matchAll"),
  replace: Symbol("Symbol.replace"),
  search: Symbol("Symbol.search"),
  species: Symbol("Symbol.species"),
  split: Symbol("Symbol.split"),
  toPrimitive: Symbol("Symbol.toPrimitive"),
  toStringTag: Symbol("Symbol.toStringTag"),
  unscopables: Symbol("Symbol.unscopables"),
}
*/

І ви їх використовуєте, навіть не усвідомлюючи цього. Наприклад, викликаючи цикл for на масиві:

const arr = [1,2,3]

for (const num of arr) {
  console.log(num)
}

// 1
// 2
// 3

У масивів є прихований метод, який вираховує та повертає значення для кожної ітерації (такі функції називаються ітераторами). А захований цей метод за символом Symbol.iterator.

Тобто, під час роботи циклу рушій JavaScript викликає прихований метод `arr[Symbol.iterator]()` та записує його результат в змінну num. І повторює цей процес доти, доки `arr[Symbol.iterator]()` повертає бодай щось.

І ми можемо змінювати поведінку JavaScript змінюючи приховані методи за такими символами:

const arr = [1,2,3]

arr[Symbol.iterator] = function* () {
  yield 'Що це?';
  yield 'Це взагалі законно?';
  yield 'Чортівня! 🪄';
} 

for (const num of arr) {
  console.log(num)
}

// Що це?
// Це взагалі законно?
// Чортівня! 🪄

Змінивши метод за Symbol.iterator ми фактично переписали реалізацію перебору значень масиву. І це працює не лише для циклів

const newArr = [...arr]
console.log(newArr)
// [ "Що це?", "Це взагалі законно?", "Чортівня! 🪄" ]

Шпаргалка по JavaScript Symbol-ам

Symbol.hasInstance

Метод, який визначає, чи розпізнає об’єкт-конструктор інший об’єкт як свій екземпляр. Використовується в `instanceof`.

obj instanceof Array // obj[Symbol.hasInstance](Array)

Symbol.isConcatSpreadable

Логічне значення, яке визначає, чи потрібно “розгортати” значення при конкатенації з масивом, чи залишати як є. Використовується в `Array.prototype.concat()`.

const arr1 = [1,2,3]
const arr2 = [4,5,6]

console.log(arr1.concat(arr2)) // [1,2,3,4,5,6]

arr2[Symbol.isConcatSpreadable] = false

console.log(arr1.concat(arr2)) // [1,2,3,[4,5,6]]

Symbol.iterator та Symbol.asyncIterator

Про цього написав трохи вище. Методи, які повертають ітератори об’єкта.

Symbol.match та Symbol.matchAll

Методи які використовуються в `String.prototype.match()` та `String.prototype.matchAll()` відповідно.

'foo'.match(obj)    // obj[Symbol.match]('foo')
'foo'.matchAll(obj) // obj[Symbol.matchAll]('foo')

Symbol.replace

Метод, який визначає як буде замінено частину рядка. Використовується в `String.prototype.replace()`.

'foo'.replace(obj, 'bar') // obj[Symbol.replace]('foo', 'bar')

Symbol.search

Метод який повертає індекс символу який відповідає об’єкту. Використовується в `String.prototype.search()`.

'foo'.search(obj) // obj[Symbol.search]('foo')

Symbol.species

Функція конструктор. Методи, що створюють копії об’єктів, можуть звертатись до цього символу, щоб змінювати прототип для новоствореної копії.

class MyArray extends Array {
  // Визначає, що всі копії будуть вважати Array за батьківський конструктор
  static get [Symbol.species]() {
    return Array;
  }
}
const a = new MyArray(1, 2, 3);
const mapped = a.map((x) => x * x);

console.log(a.constructor); // MyArray 
console.log(mapped.constructor); // Array

Symbol.split

Метод, який розрізає рядок за переданим регулярним виразом. Використовується в `String.prototype.split()`.

'foo'.split(obj, limit) // obj[Symbol.split]('foo', limit)

Symbol.toPrimitive

Метод, який конвертує об’єкт в примітив. Використовується при приведенні типів.

const obj = {};
console.log(+obj);     // NaN
console.log(`${obj}`); // "[object Object]"
console.log(obj + ""); // "[object Object]"

// Змінюємо алгоритм конвертації об'єкту в примітивні значення.
obj[Symbol.toPrimitive] = function(hint) {
  if (hint === "number") {
    return 42;
  }
  if (hint === "string") {
    return "Привіт";
  }
  return true;
};

console.log(+obj);     // 42       — hint === "number"
console.log(`${obj}`); // "Привіт" — hint === "string"
console.log(obj + ""); // "true"   — hint === "default"

Symbol.unscopables

Об’єкт, ключі якого буде виключено з області видимості with

const obj {
  name: 'Alex'
  password: '1234'

  [Symbol.unscopables]: {
    password: true
  }
}

with(obj) {
  console.log(name) // Alex
  console.log(password) // undefined
}

Підсумок

Як бачите, чимала частина “внутрішньої” поведінки JavaScript визначена в прихованих за символами методах. І хоч я й називаю їх прихованими, насправді ви вільні маніпулювати ними як завгодно, створювати власні унікальні класи з нестандартною поведінкою.

Статті про вітчизняний бізнес та цікавих людей:

  • Вітаємо з Різдвом Христовим!

    Друкарня та платформа WE.UA вітають всіх наших читачів та авторів зі світлим святом Різдва! Зичимо всім українцям довгожданого миру, міцного здоровʼя, злагоди, родинного затишку та втілення всього доброго і прекрасного, чого вам побажали колядники!

    Теми цього довгочиту:

    Різдво
  • Каблучки – прикраси, які варто купувати

    Ювелірні вироби – це не тільки спосіб витратити гроші, але і зробити вигідні інвестиції. Бо вартість ювелірних виробів з кожним роком тільки зростає. Тому купуючи стильні прикраси, ви вигідно вкладаєте кошти.

    Теми цього довгочиту:

    Як Вибрати Каблучку
  • П'ять помилок у виборі домашнього текстилю, які псують комфорт сну

    Навіть ідеальний матрац не компенсує дискомфорт, якщо текстиль підібрано неправильно. Постільна білизна безпосередньо впливає на терморегуляцію, стан шкіри та глибину сну. Більшість проблем виникає не через низьку якість виробів, а через вибір матеріалів та подальшу експлуатацію

    Теми цього довгочиту:

    Домашній Текстиль
  • Як знайти житло в Києві

    Переїжджаєте до Києва і шукаєте житло? Дізнайтеся, як орендувати чи купити квартиру, перевірити власника та знайти варіанти, про які зазвичай не говорять.

    Теми цього довгочиту:

    Агентство Нерухомості
  • Як заохотити дитину до читання?

    Як залучити до читання сучасну молодь - поради та факти. Користь читання для дітей - основні переваги. Розвиток дітей - це наше майбутнє.

    Теми цього довгочиту:

    Читання
Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Олександр Козак
Олександр Козак@kozack

9.7KПрочитань
1Автори
68Читачі
Підтримати
На Друкарні з 14 квітня

Більше від автора

  • Детальний огляд семантики HTML теґів. Різниця між <section> та <article>

    Огляд семантики HTML: розрізнення між <section> та <article>, значення правильного використання тегів та їх роль у структурі вебсторінки. Дослідження важливості семантики для SEO та доступності, а також рекомендації щодо використання HTML-елементів та ролей

    Теми цього довгочиту:

    Html
  • Про доступність та UI на прикладі мого особистого сайту

    Знайомтесь це мій особистий сайт. Перший знімок те яким він був ДО другий - ПІСЛЯ сьогоднішнього патчу. І в цій короткій статті я хочу зробити маленьке ревью та розказати на прикладах ЧОМУ я реалізував деякі дивні речі.

    Теми цього довгочиту:

    Доступність
  • Як зробити нескінченну прокрутку на сайті. Або 10 недоліків та одна перевага Infinity Scroll

    В цій статті я хочу описати 10 поширених проблем, пов’язаних з нескінченною прокруткою, які розробнику доведеться вирішувати при реалізації Infinity Scroll. Та про єдину причину, чому попри всі недоліки нескінченну прокрутку активно використовують.

    Теми цього довгочиту:

    Ui-ux

Це також може зацікавити:

  • 1 день = 1 допис

    Нещодавно прочитав десь, що в нашому ритмі життя, з усім цим хаосом, зі всіма новинами переважно не позитивними нам просто потрібно краплина чогось доброго, світлого...

    Теми цього довгочиту:

    Думки

Коментарі (3)

Класний матеріал, дякую! Особливо повеселилась на моменті, де можна переписати цикл for. Збираюсь тепер трохи потролити своїх джунів)))

Це також може зацікавити:

  • 1 день = 1 допис

    Нещодавно прочитав десь, що в нашому ритмі життя, з усім цим хаосом, зі всіма новинами переважно не позитивними нам просто потрібно краплина чогось доброго, світлого...

    Теми цього довгочиту:

    Думки