Символ — это один из примитивных типов данных в JavaScript, он представляет собой уникальное неизменное значение, обычно используемое в качестве ключевого значения свойств объекта. Поскольку значения Symbol уникальны, свойства объекта защищены от случайной перезаписи или изменения. Ниже приведены методы и атрибуты Symbol:
Атрибуты
Символ.длина
Значение атрибута длины конструктора Symbol равно 0.
Образец кода:
console.log(Symbol.length); // 0
метод
Символ. для()
Метод Symbol.for() вернет существующее значение символа на основе заданного строкового ключа. Если нет, новое значение символа создается и регистрируется в глобальном реестре символов.
Образец кода:
const symbol1 = Symbol.for('foo'); const symbol2 = Symbol.for('foo'); console.log(symbol1 === symbol2); // true
Сценарий использования: Когда нам нужно использовать глобально уникальное значение Symbol, мы можем использовать метод Symbol.for() для получения или создания значения. Например, когда определенное значение Symbol совместно используется несколькими модулями, мы можем использовать Symbol.for(), чтобы убедиться, что полученное значение Symbol уникально.
Символ. ключ для()
Метод Symbol.keyFor() возвращает ключ существующего значения Symbol. Возвращает неопределенное значение, если данное значение символа не существует в глобальном реестре символов.
Образец кода:
const symbol1 = Symbol.for('foo'); const key1 = Symbol.keyFor(symbol1); const symbol2 = Symbol('bar'); const key2 = Symbol.keyFor(symbol2); console.log(key1); // 'foo' console.log(key2); // undefined
Сценарий использования: Когда нам нужно получить глобально уникальный ключ значения Symbol, мы можем использовать метод Symbol.keyFor(). Однако следует отметить, что только когда значение Symbol зарегистрировано в глобальном реестре Symbol, метод Symbol.keyFor() можно использовать для получения его ключа.
Символ()
Функция Symbol() возвращает новое уникальное значение Symbol. Вы можете использовать описание дополнительного параметра, чтобы добавить описание значения символа.
Образец кода:
const symbol1 = Symbol('foo'); const symbol2 = Symbol('foo'); console.log(symbol1 === symbol2); // false
Сценарий использования: Когда нам нужно использовать уникальное значение символа, мы можем использовать функцию Symbol() для создания значения. Как правило, мы будем использовать значения Symbol в качестве ключевых значений свойств объекта, чтобы гарантировать, что свойство не может быть случайно перезаписано или изменено.
Символ.прототип.toString()
Метод Symbol.prototype.toString() возвращает строковое представление значения Symbol, которое содержит описание, указанное при создании функции Symbol().
Образец кода:
const symbol = Symbol('foo'); console.log(symbol.toString()); // 'Symbol(foo)'
Сценарий использования: Когда нам нужно преобразовать значение Symbol в строку, мы можем использовать метод Symbol.prototype.toString().
Символ.прототип.значение()
Метод Symbol.prototype.valueOf() возвращает само значение Symbol.
Образец кода:
const symbol = Symbol('foo'); console.log(symbol.valueOf()); // Symbol(foo)
Сценарий использования: Когда нам нужно получить само значение Symbol, мы можем использовать метод Symbol.prototype.valueOf().
Символ. итератор
Symbol.iterator — это предопределенное значение Symbol, представляющее метод итератора по умолчанию для объекта. Этот метод возвращает объект итератора, который можно использовать для перебора всех проходимых свойств объекта.
Образец кода:
const obj = { a: 1, b: 2 }; for (const key of Object.keys(obj)) { console.log(key); } // Output: // 'a' // 'b' for (const key of Object.getOwnPropertyNames(obj)) { console.log(key); } // Output: // 'a' // 'b' for (const key of Object.getOwnPropertySymbols(obj)) { console.log(key); } // Output: // No output obj[Symbol.iterator] = function* () { for (const key of Object.keys(this)) { yield key; } } for (const key of obj) { console.log(key); } // Output: // 'a' // 'b'
Сценарий использования: когда нам нужно настроить поведение итерации объекта, мы можем добиться этого, определив свойство Symbol.iterator. Например, для пользовательской структуры данных мы можем определить ее метод Symbol.iterator, чтобы его можно было пройти с помощью оператора for…of.
Символ.hasInstance
Symbol.hasInstance — это предопределенное значение Symbol, используемое для определения поведения оператора instanceof объекта. Когда метод Symbol.hasInstance существует в цепочке прототипов объекта, этот объект может использоваться оператором instanceof.
Образец кода:
class Foo { static [Symbol.hasInstance](obj) { return obj instanceof Array; } } console.log([] instanceof Foo); // true console.log({} instanceof Foo); // fals
Сценарий использования: когда нам нужно настроить поведение instanceof объекта, мы можем добиться этого, определив метод Symbol.hasInstance.
Symbol.isConcatSpreadable
Symbol.isConcatSpreadable — это предопределенное значение Symbol, используемое для определения поведения расширения объекта при использовании метода concat(). Если свойство объекта Symbol.isConcatSpreadable имеет значение false, объект не будет расширен при вызове метода concat().
Образец кода:
const arr1 = [1, 2]; const arr2 = [3, 4]; const obj = { length: 2, 0: 5, 1: 6, [Symbol.isConcatSpreadable]: false }; console.log(arr1.concat(arr2)); // [1, 2, 3, 4] console.log(arr1.concat(obj)); // [1, 2, { length: 2, 0: 5, 1: 6, [Symbol(Symbol.isConcatSpreadable)]: false }]
Сценарий использования: когда нам нужно настроить поведение расширения объекта при использовании метода concat(), это можно сделать, определив свойство Symbol.isConcatSpreadable.
Символ.toPrimitive
Symbol.toPrimitive — это предопределенное значение Symbol, используемое для определения поведения объекта при его преобразовании. Если объект определяет метод Symbol.toPrimitive, этот метод вызывается при преобразовании объекта в примитивное значение.
Образец кода:
const obj = { valueOf() { return 1; }, [Symbol.toPrimitive](hint) { if (hint === 'number') { return 2; } else if (hint === 'string') { return 'foo'; } else { return 'default'; } } }; console.log(+obj); // 2 console.log(`${obj}`); // 'foo' console.log(obj + ''); // 'default'
Сценарий использования: Когда нам нужно настроить поведение объекта при его приведении, это можно сделать, определив метод Symbol.toPrimitive.
Символ.toStringTag
Symbol.toStringTag — это предопределенное значение Symbol, которое используется для определения строки, возвращаемой объектом при вызове метода Object.prototype.toString(). Если объект определяет свойство Symbol.toStringTag, при вызове метода объекта toString() будет возвращена строка, соответствующая свойству.
Образец кода:
class Foo { get [Symbol.toStringTag]() { return 'Bar'; } } console.log(Object.prototype.toString.call(new Foo())); // '[object Bar]'
Сценарий использования: когда нам нужно настроить строку, возвращаемую объектом при вызове метода Object.prototype.toString(), это можно сделать, определив свойство Symbol.toStringTag.
Символ.виды
Symbol.species — это предопределенное значение Symbol, используемое для определения конструктора производных объектов. Если объект определяет свойство Symbol.species, при вызове производного метода объекта (например, Array.prototype.map()) возвращаемый новый объект будет использовать конструктор, указанный в свойстве.
Образец кода:
class MyArray extends Array { static get [Symbol.species]() { return Array; } } const myArr = new MyArray(1, 2, 3); const arr = myArr.map(x => x * 2); console.log(arr instanceof MyArray); // false console.log(arr instanceof Array); // true
Сценарий использования: когда нам нужно настроить конструктор производного объекта, это можно сделать, определив свойство Symbol.species.
Символ.матч
Symbol.match — это предопределенное значение Symbol, используемое для определения поведения объекта при вызове метода String.prototype.match(). Если объект определяет метод Symbol.match, при вызове метода match() объекта метод будет вызываться для сопоставления.
Образец кода:
class Foo { [Symbol.match](str) { return str.indexOf('foo') !== -1; } } console.log('foobar'.match(new Foo())); // true console.log('barbaz'.match(new Foo())); // false
Сценарий использования: когда нам нужно настроить поведение объекта при вызове метода String.prototype.match(), это можно сделать, определив метод Symbol.match.
Символ.заменить
Symbol.replace — это предопределенное значение Symbol, используемое для определения поведения объекта при вызове метода String.prototype.replace(). Если объект определяет метод Symbol.replace, при вызове метода replace() объекта будет вызван метод для замены.
Образец кода:
class Foo { [Symbol.replace](str, replacement) { return str.replace('foo', replacement); } } console.log('foobar'.replace(new Foo(), 'baz')); // 'bazbar' console.log('barbaz'.replace(new Foo(), 'baz')); // 'barbaz'
Сценарий использования: когда нам нужно настроить поведение объекта при вызове метода String.prototype.replace(), это можно сделать, определив метод Symbol.replace.
Символ.поиск
Symbol.search — это предопределенное значение Symbol, используемое для определения поведения объекта при вызове метода String.prototype.search(). Если объект определяет Symbol.search
class Foo { [Symbol.search](str) { return str.indexOf('foo'); } } console.log('foobar'.search(new Foo())); // 0 console.log('barbaz'.search(new Foo())); // -1
Сценарий использования: когда нам нужно настроить поведение объекта при вызове метода String.prototype.search(), это можно сделать, определив метод Symbol.search.
Символ. расколоть
Symbol.split — это предопределенное значение Symbol, используемое для определения поведения объекта при вызове метода String.prototype.split(). Если объект определяет метод Symbol.split, при вызове метода split() объекта этот метод будет вызываться для разделения.
Образец кода:
class Foo { [Symbol.split](str) { return str.split(' '); } } console.log('foo bar baz'.split(new Foo())); // ['foo', 'bar', 'baz'] console.log('foobarbaz'.split(new Foo())); // ['foobarbaz']
Сценарий использования: когда нам нужно настроить поведение объекта при вызове метода String.prototype.split(), это можно сделать, определив метод Symbol.split.
Символ. итератор
Symbol.iterator — это предопределенное значение Symbol, используемое для определения поведения объекта при обходе. Если объект определяет метод Symbol.iterator, вы можете использовать циклы for…of, операторы распространения и т. д. для обхода объекта.
Образец кода:
class Foo { constructor() { this.items = ['foo', 'bar', 'baz']; } *[Symbol.iterator]() { for (const item of this.items) { yield item; } } } const foo = new Foo(); for (const item of foo) { console.log(item); } // 'foo' // 'bar' // 'baz'
Сценарий использования: когда нам нужно настроить поведение объекта при его обходе, это можно сделать, определив метод Symbol.iterator. Например, мы можем поддерживать обход пользовательских структур данных, реализуя метод Symbol.iterator.
Символ.toPrimitive
Symbol.toPrimitive — это предопределенное значение Symbol, используемое для определения поведения объекта при его преобразовании. Если объект определяет метод Symbol.toPrimitive, его можно привести, вызвав этот метод.
Образец кода:
const obj = { valueOf() { return 1; }, [Symbol.toPrimitive](hint) { if (hint === 'default') { return 'default'; } else if (hint === 'number') { return 2; } else { return 'foo'; } } }; console.log(+obj); // 2 console.log(`${obj}`); // 'foo' console.log(obj + ''); // 'default'
Сценарий использования: Когда нам нужно настроить поведение объекта при его приведении, это можно сделать, определив метод Symbol.toPrimitive.
Символ.toStringTag
Symbol.toStringTag — это предопределенное значение Symbol, которое используется для определения строки, возвращаемой объектом при вызове метода Object.prototype.toString(). Если объект определяет свойство Symbol.toStringTag, при вызове метода объекта toString() будет возвращена строка, соответствующая свойству.
Образец кода:
class Foo { get [Symbol.toStringTag]() { return 'Bar'; } } console.log(Object.prototype.toString.call(new Foo())); // '[object Bar]'
Сценарий использования: когда нам нужно настроить строку, возвращаемую объектом при вызове метода Object.prototype.toString(), это можно сделать, определив свойство Symbol.toStringTag. Это помогает нам более четко представлять тип объекта.
Символ. недоступное
Symbol.unscopables — это предопределенное значение Symbol, используемое для определения поведения объекта при использовании оператора with. Если объект определяет свойство Symbol.unscopables, при использовании оператора with указанные свойства объекта не будут привязаны к среде оператора with.
Образец кода:
const obj = { a: 1, b: 2, c: 3, [Symbol.unscopables]: { c: true } }; with (obj) { console.log(a); // 1 console.log(b); // 2 console.log(c); // ReferenceError: c is not defined }
Сценарий использования: Поскольку оператор with вызовет некоторые проблемы с безопасностью и производительностью, не рекомендуется использовать его в реальной разработке. Однако, если вам действительно нужно использовать оператор with, вы можете предотвратить ошибочную привязку определенных свойств к среде оператора with, определив свойство Symbol.unscopables.
Символ.hasInstance
Symbol.hasInstance — это предопределенное значение Symbol, используемое для определения поведения объекта при вызове оператора instanceof. Если объект определяет метод Symbol.hasInstance, при вызове оператора instanceof объекта этот метод будет вызываться, чтобы определить, является ли целевой объект экземпляром объекта.
Образец кода:
class Foo { static [Symbol.hasInstance](obj) { return Array.isArray(obj); } } console.log([] instanceof Foo); // true console.log({} instanceof Foo); // false
Сценарий использования: Когда нам нужно настроить поведение объекта при вызове оператора instanceof, это можно сделать, определив метод Symbol.hasInstance. Например, мы можем поддерживать оценку пользовательских типов данных, реализуя метод Symbol.hasInstance.
Подведем итог
Символ — это новый базовый тип данных в ES6, который используется для представления уникальных значений. Значения символов решают проблему конфликтов имен атрибутов на уровне языка и могут использоваться в качестве имен атрибутов объектов без случайной перезаписи. Кроме того, Symbol также имеет следующие характеристики:
- Значения Symbol уникальны, и каждое значение Symbol уникально, даже если значения Symbol созданы с одной и той же строкой описания, они не будут равны;
- Значения символов могут использоваться в качестве имен свойств объектов и не будут случайно перезаписаны;
- Значения символов можно использовать как частные свойства, т.к. свойства символов в объектах недоступны вне объекта;
- Значения символов можно использовать как константы, поскольку они уникальны;
- Значения символов можно использовать для определения расширенных функций, таких как итераторы, правила преобразования типов, частные свойства и метапрограммирование.
При использовании Символа необходимо обратить внимание на следующие моменты:
- Значения символа нельзя создавать с помощью оператора new;
- Значения символов могут быть созданы путем описания строк, но строки описания не являются уникальными идентификаторами значений символов;
- Доступ к свойствам символа должен осуществляться с помощью [] при использовании, а расширение . нельзя использовать оператор;
- Несколько свойств символов в одном объекте независимы и не влияют друг на друга.
Короче говоря, Symbol — очень полезный тип данных с очень широким спектром приложений в JavaScript. Использование Symbol может эффективно избежать проблемы конфликтов имен атрибутов и может предоставить некоторые дополнительные функции для объектов. Знание Symbol поможет нам писать более надежный, эффективный и удобный в сопровождении код JavaScript.
Дополнительные материалы на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .