From c8b4d3bc10e27b42119fb93cdbdf5bc474a3ec44 Mon Sep 17 00:00:00 2001 From: Taras Kulchytskyi Date: Thu, 22 Jul 2021 20:29:12 +0300 Subject: [PATCH] Symbol type --- 1-js/04-object-basics/08-symbol/article.md | 187 +++++++++++---------- 1 file changed, 94 insertions(+), 93 deletions(-) diff --git a/1-js/04-object-basics/08-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md index 626eedb53..feb33a2ce 100644 --- a/1-js/04-object-basics/08-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -1,31 +1,31 @@ -# Symbol type +# Тип даних Символ -By specification, object property keys may be either of string type, or of symbol type. Not numbers, not booleans, only strings or symbols, these two types. +За специфікацією, ключами об’єкта можуть бути рядок, або символ. Не цифри, не логічні значення, лише рядки або символи, тільки ці два типи. -Till now we've been using only strings. Now let's see the benefits that symbols can give us. +До цього часу ми використовували лише рядки. А тепер давайте подивимося, які переваги можуть дати нам символи. -## Symbols +## Символи -A "symbol" represents a unique identifier. +"Символ" являє собою унікальний ідентифікатор. -A value of this type can be created using `Symbol()`: +Створити символ можна за допомогою `Symbol()`: ```js -// id is a new symbol +// id - це новостворенний символ let id = Symbol(); ``` -Upon creation, we can give symbol a description (also called a symbol name), mostly useful for debugging purposes: +Після створення символу ми можемо надати йому опис (так званe ім’я символу), в основному це корисно для процесу налагодження: ```js -// id is a symbol with the description "id" +// Створюємо символ id з описом (іменем) "id" let id = Symbol("id"); ``` -Symbols are guaranteed to be unique. Even if we create many symbols with the same description, they are different values. The description is just a label that doesn't affect anything. +Символи гарантовано будуть унікальними. Навіть якщо ми створюємо багато символів з однаковим описом, вони мають різні значення. Опис - це просто мітка, яка ні на що не впливає. -For instance, here are two symbols with the same description -- they are not equal: +Наприклад, ось два символи з однаковим описом -- вони не рівні: ```js run let id1 = Symbol("id"); @@ -36,12 +36,12 @@ alert(id1 == id2); // false */!* ``` -If you are familiar with Ruby or another language that also has some sort of "symbols" -- please don't be misguided. JavaScript symbols are different. +Якщо ви знайомі з Ruby чи іншою мовою програмування, яка також має «символи» - будь ласка, не думайте що це те саме. Символи в JavaScript мають свої особливості. -````warn header="Symbols don't auto-convert to a string" -Most values in JavaScript support implicit conversion to a string. For instance, we can `alert` almost any value, and it will work. Symbols are special. They don't auto-convert. +````warn header="Символи не перетворюються автоматично в рядок" +Більшість значень у JavaScript підтримують неявне перетворення в рядок. Наприклад, ми можемо помістити майже будь-яке значення в `alert`, і воно автоматично перетворить його в рядок. Символи - вони особливі. Вони не перетворюються автоматично. -For instance, this `alert` will show an error: +Наприклад, цей `alert` видасть помилку: ```js run let id = Symbol("id"); @@ -50,17 +50,17 @@ alert(id); // TypeError: Cannot convert a Symbol value to a string */!* ``` -That's a "language guard" against messing up, because strings and symbols are fundamentally different and should not accidentally convert one into another. +Це "захист" мови від плутанини, оскільки рядки та символи принципово відрізняються і не повинні неконтрольовано перетворюватись з одного в інше. -If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here: +Якщо ми дійсно хочемо відобразити символ, нам потрібно явно перетворити його за допомогою `.toString()`, ось так: ```js run let id = Symbol("id"); *!* -alert(id.toString()); // Symbol(id), now it works +alert(id.toString()); // Symbol(id), тепер все працює */!* ``` -Or get `symbol.description` property to show the description only: +Або викликати властивість `symbol.description` щоб відобразити тільки опис: ```js run let id = Symbol("id"); *!* @@ -70,16 +70,16 @@ alert(id.description); // id ```` -## "Hidden" properties +## "Приховані" властивості -Symbols allow us to create "hidden" properties of an object, that no other part of code can accidentally access or overwrite. +Символи дозволяють нам створювати "приховані" властивості об’єкта, до яких жодна інша частина програми не може випадково отримати доступ або перезаписати їх. -For instance, if we're working with `user` objects, that belong to a third-party code. We'd like to add identifiers to them. +Наприклад, якщо ми працюємо з `user` об’єктами, які належать сторонньому коду. Ми хотіли б додати до них ідентифікатори. -Let's use a symbol key for it: +Використаємо для цього ключ символа: ```js run -let user = { // belongs to another code +let user = { // належить сторонньому коду name: "John" }; @@ -87,83 +87,83 @@ let id = Symbol("id"); user[id] = 1; -alert( user[id] ); // we can access the data using the symbol as the key +alert( user[id] ); // ми можемо отримати доступ до даних, використовуючи символ як ключ ``` -What's the benefit of using `Symbol("id")` over a string `"id"`? +Яка користь від використання `Symbol("id")` замість рядка `"id"`? -As `user` objects belongs to another code, and that code also works with them, we shouldn't just add any fields to it. That's unsafe. But a symbol cannot be accessed accidentally, the third-party code probably won't even see it, so it's probably all right to do. +Оскільки об’єкт `user` належить сторонньому коду, і цей код також працює з ними, нам не варто просто додавати до нього будь-які поля. Це небезпечно. Але до символу неможливо отримати доступ випадково, сторонній код, ймовірно, навіть не побачить його, тому, додавання поля до об’єкта не викличе ніяких проблем. -Also, imagine that another script wants to have its own identifier inside `user`, for its own purposes. That may be another JavaScript library, so that the scripts are completely unaware of each other. +Крім того, уявіть, що інший скрипт хоче мати власний ідентифікатор всередині `user` для своїх цілей. Це може бути ще одна бібліотека JavaScript, так що сценарії абсолютно не знають один про одного. -Then that script can create its own `Symbol("id")`, like this: +Тоді цей скрипт може створити свій власний `Symbol("id")`, як ось цей: ```js // ... let id = Symbol("id"); -user[id] = "Their id value"; +user[id] = "Їхній ідентифікатор"; ``` -There will be no conflict between our and their identifiers, because symbols are always different, even if they have the same name. +Конфлікту не буде між нашим та їх ідентифікаторами, оскільки символи завжди різні, навіть якщо вони мають однакову назву. -...But if we used a string `"id"` instead of a symbol for the same purpose, then there *would* be a conflict: +...Але якби ми використовували рядок `"id"` замість символу з тією ж метою, тоді *виникне* конфлікт ```js -let user = { name: "John" }; +let user = { name: "Тарас" }; -// Our script uses "id" property -user.id = "Our id value"; +// Наш скрипт використовує ключ "id" +user.id = "Наш ідентифікатор"; -// ...Another script also wants "id" for its purposes... +// ...Інший скрипт теж хоче використовувати ключ "id" для своїх цілей... -user.id = "Their id value" -// Boom! overwritten by another script! +user.id = "Їхній ідентифікатор" +// Ой! Властивість перезаписана стороннім скриптом! ``` -### Symbols in an object literal +### Символи в літералі об’єкта -If we want to use a symbol in an object literal `{...}`, we need square brackets around it. +Якщо ми хочемо використовувати символ у літералі об’єкта `{...}`, нам потрібні обгорнути його в квадратні дужки. -Like this: +Ось так: ```js let id = Symbol("id"); let user = { - name: "John", + name: "Тарас", *!* - [id]: 123 // not "id": 123 + [id]: 123 // просто "id": 123 не спрацює */!* }; ``` -That's because we need the value from the variable `id` as the key, not the string "id". +Це тому, що нам потрібно використовувати значення змінної `id` як ключ, а не рядок "id". -### Symbols are skipped by for..in +### Символи ігноруються циклом for..in -Symbolic properties do not participate in `for..in` loop. +Властивості в якості символів не перебираються `for..in` циклом. -For instance: +Наприклад: ```js run let id = Symbol("id"); let user = { - name: "John", + name: "Тарас", age: 30, [id]: 123 }; *!* -for (let key in user) alert(key); // name, age (no symbols) +for (let key in user) alert(key); // name, age (дані ключі не є символами) */!* -// the direct access by the symbol works -alert( "Direct: " + user[id] ); +// але працює прямий доступ за допомогою символу +alert( "Прямий доступ: " + user[id] ); ``` -`Object.keys(user)` also ignores them. That's a part of the general "hiding symbolic properties" principle. If another script or a library loops over our object, it won't unexpectedly access a symbolic property. +`Object.keys(user)` також ігнорує їх. Це частина загального принципу "приховування символьних властивостей". Якщо інший скрипт або бібліотека спробує перебрати наш об’єкт за допомогою цикла, він несподівано не отримає доступ до символьних властивостей. -In contrast, [Object.assign](mdn:js/Object/assign) copies both string and symbol properties: +А ось, [Object.assign](mdn:js/Object/assign) копіює властивості рядка та символу: ```js run let id = Symbol("id"); @@ -176,102 +176,103 @@ let clone = Object.assign({}, user); alert( clone[id] ); // 123 ``` -There's no paradox here. That's by design. The idea is that when we clone an object or merge objects, we usually want *all* properties to be copied (including symbols like `id`). +Тут немає парадокса. Саме так задумано. Ідея полягає в тому, що коли ми клонуємо об’єкт або об’єднуємо об’єкти, ми зазвичай хочемо скопіювати *всі* властивості (включаючи і властивості з ключами в якості символу, як наприклад `id` з прикладу вище). -## Global symbols +## Глобальні символи -As we've seen, usually all symbols are different, even if they have the same name. But sometimes we want same-named symbols to be same entities. For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property. +Як ми вже бачили, зазвичай усі символи унікальні, навіть якщо вони мають однакову назву. Але іноді ми хочемо, щоб однойменні символи були однаковими сутностями. Наприклад, різні частини нашого додатку хочуть отримати доступ до символу `"id"`, що означає абсолютно однакову властивість. -To achieve that, there exists a *global symbol registry*. We can create symbols in it and access them later, and it guarantees that repeated accesses by the same name return exactly the same symbol. +Для цього існує *глобальний реєстр символів*. Ми можемо створити в ньому символи і отримати до них доступ пізніше, і це гарантує, що повторні звернення з тим самим іменем нам повернуть абсолютно однаковий символ. -In order to read (create if absent) a symbol from the registry, use `Symbol.for(key)`. +Для того, щоб знайти (створити, якщо його немає) символ у реєстрі, використовуйте `Symbol.for(key)`. -That call checks the global registry, and if there's a symbol described as `key`, then returns it, otherwise creates a new symbol `Symbol(key)` and stores it in the registry by the given `key`. +Цей виклик перевіряє глобальний реєстр, і якщо є символ з іменем `key`, тоді повертає його, інакше створює новий символ `Symbol(key)` і зберігає його в реєстрі за вказаним `key`. -For instance: +Наприклад: ```js run -// read from the global registry -let id = Symbol.for("id"); // if the symbol did not exist, it is created +// шукаємо в глобального реєстрі +let id = Symbol.for("id"); // якщо такого символу немає, він буде створений -// read it again (maybe from another part of the code) +// шукаємо знову, але присвоюємо в іншу змінну (можливо в іншій частині коду) let idAgain = Symbol.for("id"); -// the same symbol +// як бачимо, це один і той самий символ alert( id === idAgain ); // true ``` -Symbols inside the registry are called *global symbols*. If we want an application-wide symbol, accessible everywhere in the code -- that's what they are for. +Символи всередині реєстру називаються *глобальні символи*. Якщо вам потрібні символи, доступні скрізь у коді - використовуйте глобальні символи. -```smart header="That sounds like Ruby" -In some programming languages, like Ruby, there's a single symbol per name. +```smart header="Схоже як в Ruby" +У деяких мовах програмування, таких як Ruby, для одного імені використовується один символ. Не можуть існувати різні символи з однаковими іменами. -In JavaScript, as we can see, that's right for global symbols. +Як бачимо, в JavaScript, це правило теж працює, але тільки для глобальних символів. ``` ### Symbol.keyFor -For global symbols, not only `Symbol.for(key)` returns a symbol by name, but there's a reverse call: `Symbol.keyFor(sym)`, that does the reverse: returns a name by a global symbol. +Для глобальних символів, не тільки `Symbol.for(key)` повертає символ за іменем, також існує протилежний метод: `Symbol.keyFor(sym)`, який працює наоборот: приймає глобальний символ і повертає його ім’я. -For instance: +Наприклад: ```js run -// get symbol by name +// отримуємо символ за іменем let sym = Symbol.for("name"); let sym2 = Symbol.for("id"); -// get name by symbol +// отримуємо ім’я за символом alert( Symbol.keyFor(sym) ); // name alert( Symbol.keyFor(sym2) ); // id ``` -The `Symbol.keyFor` internally uses the global symbol registry to look up the key for the symbol. So it doesn't work for non-global symbols. If the symbol is not global, it won't be able to find it and returns `undefined`. +`Symbol.keyFor` внутрішньо використовує глобальний реєстр символів для пошуку ключа символу. Тож це не працює для неглобальних символів. Якщо символ не є глобальним, він не зможе його знайти і повернем нам `undefined`. -That said, any symbols have `description` property. +Тим не менш, будь-які символи мають властивість `description`. -For instance: +Наприклад: ```js run let globalSymbol = Symbol.for("name"); let localSymbol = Symbol("name"); -alert( Symbol.keyFor(globalSymbol) ); // name, global symbol -alert( Symbol.keyFor(localSymbol) ); // undefined, not global +alert( Symbol.keyFor(globalSymbol) ); // name, глобальний символ +alert( Symbol.keyFor(localSymbol) ); // undefined, не глобальний сивол alert( localSymbol.description ); // name ``` -## System symbols +## Системні символи -There exist many "system" symbols that JavaScript uses internally, and we can use them to fine-tune various aspects of our objects. +Існує багато “системних” символів, які JavaScript використовує внутрішньо, і ми можемо використовувати їх для налаштування різних аспектів наших об’єктів. -They are listed in the specification in the [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols) table: +Вони вказані в таблиці специфікації [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols): - `Symbol.hasInstance` - `Symbol.isConcatSpreadable` - `Symbol.iterator` - `Symbol.toPrimitive` -- ...and so on. +- ...та інші. -For instance, `Symbol.toPrimitive` allows us to describe object to primitive conversion. We'll see its use very soon. +До прикладу, `Symbol.toPrimitive` дозволяє описати правила для об’єкта до примітивного перетворення. Ми побачимо його використання дуже скоро. -Other symbols will also become familiar when we study the corresponding language features. +З іншими системними символами познайомимось ближче, коли ми будемо вивчати відповідні мовні особливості. -## Summary +## Підсумки -`Symbol` is a primitive type for unique identifiers. +`Symbol`-- це примітивний тип даних який використовується для унікальних ідентифікаторів. -Symbols are created with `Symbol()` call with an optional description (name). +Символ створюється за допомогою виклику `Symbol()` з необов’язковим описом (ім’я). -Symbols are always different values, even if they have the same name. If we want same-named symbols to be equal, then we should use the global registry: `Symbol.for(key)` returns (creates if needed) a global symbol with `key` as the name. Multiple calls of `Symbol.for` with the same `key` return exactly the same symbol. +Символи - завжди унікальні, навіть якщо вони мають однакову назву. Якщо ми хочемо, щоб однойменні символи були рівними за значенням, тоді слід використовувати глобальний реєстр: `Symbol.for(key)` повертає (створює за потреби) глобальний символ з `key` в якості імені. +Декілька викликів `Symbol.for` з тією ж `key` повертає той самий символ. -Symbols have two main use cases: +Символи мають два основних варіанти використання: -1. "Hidden" object properties. - If we want to add a property into an object that "belongs" to another script or a library, we can create a symbol and use it as a property key. A symbolic property does not appear in `for..in`, so it won't be accidentally processed together with other properties. Also it won't be accessed directly, because another script does not have our symbol. So the property will be protected from accidental use or overwrite. +1. "Приховані" властивості об’єкта. + Якщо ми хочемо додати властивість до об’єкта, який «належить» іншому скрипту або бібліотеці, ми можемо створити символ і використовувати його як ключ. Властивість у вигляді символу не відображається в `for..in`, тому вона не буде випадково оброблена разом з іншими властивостями. Крім того, він не буде безпосередньо доступний, оскільки інший скрипт не має нашого символу. Таким чином власність буде захищена від випадкового використання або перезапису. - So we can "covertly" hide something into objects that we need, but others should not see, using symbolic properties. + Тож ми можемо ховати щось потрібне для нас в об’єкти, що сторонні не повинні бачити, використовуючи символічні властивості. -2. There are many system symbols used by JavaScript which are accessible as `Symbol.*`. We can use them to alter some built-in behaviors. For instance, later in the tutorial we'll use `Symbol.iterator` for [iterables](info:iterable), `Symbol.toPrimitive` to setup [object-to-primitive conversion](info:object-toprimitive) and so on. +2. JavaScript використовує багато системних символів, доступних як `Symbol.*`. Ми можемо використовувати їх для зміни деяких вбудованих форм поведінки. До прикладу, пізніше в підручнику ми будемо використовувати `Symbol.iterator` для [ітераторів](info:iterable), `Symbol.toPrimitive` для налаштування [перетворення об’єкта в примітив](info:object-toprimitive) та інше. -Technically, symbols are not 100% hidden. There is a built-in method [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) that allows us to get all symbols. Also there is a method named [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) that returns *all* keys of an object including symbolic ones. So they are not really hidden. But most libraries, built-in functions and syntax constructs don't use these methods. +Технічні символи не приховані на 100%. Існує вбудований метод [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) що дозволяє отримати всі символи. Також існує метод з іменем [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) що повертає *всі* ключі об’єкта, включаючи символьні. Тож вони насправді не зовсім приховані. Але більшість бібліотек, вбудованих функцій та конструкцій синтаксису не використовують ці методи. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy