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

Введение в JavaScript символы 

В ES2015 введен новый примитивный тип с именем Symbol. Это уникальный и неизменный идентификатор. Как только вы создали его, его нельзя скопировать.

Каждый раз, когда вы создаете новый символ, он уникален. Символы в основном используются для уникальных идентификаторов в объекте. Это единственная цель символа.

Есть также специальные символы, которые мы можем использовать для реализации различных операций или переопределения поведения некоторых операций по умолчанию.

Определение символов

Существуют некоторые статические свойства и собственные методы, которые предоставляют глобальный реестр символов. Это похоже на встроенный объект, но у него нет конструктора, поэтому мы не можем написать, new Symbol чтобы создать объект символа с ключевым словом new.

Чтобы создать новые символы, мы можем написать:

const fooSymbol = Symbol('foo')

Обратите внимание, что каждый раз, когда мы вызываем функцию Symbol, мы получаем новый символ, поэтому, если мы напишем:

Symbol('sym') === Symbol('sym')

Выражение выше вернет false. Это потому, что каждый символ уникален.

Встроенные методы

Существуют встроенные символы, которые используются в качестве идентификаторов для различных методов и значений. Методы с некоторыми символами вызываются, когда используются некоторые операторы.

Symbol.hasInstance

Это метод, который проверяет, является ли объект экземпляром данного конструктора. Этот метод вызывается, когда вызывается оператор instanceof.

Мы можем переопределить метод Symbol.hasInstance следующим образом:

class Foo {  
  static [Symbol.hasInstance](instance) {
    return typeof instance.foo != 'undefined';
  }
}
console.log({ foo: 'abc' } instanceof Foo);

В приведенном выше коде мы определили, что объект является экземпляром класса Foo, если есть значение для свойства foo. Следовательно, { foo: ‘abc’ } instanceof Foo должен вернуть true, поскольку для него установлено свойство.

Symbol.isConcatSpreadable

Symbol.isConcatSpreadable является логическим значением, которое указывает, должен ли объект быть сведен в массив методом concat.

Мы можем использовать его как в следующем коде:

const arr1 = ['a', 'b', 'c'];
const arr2 = [true, false];
let arr3 = arr1.concat(arr2);
console.log(arr3);
arr2[Symbol.isConcatSpreadable] = false;
arr3 = arr1.concat(arr2);
console.log(arr3);

Первый console.log должен вывести:

["a", "b", "c", true, false]

А второй должен вывести:

["a", "b", "c", Array(2)]

Это связано с тем, что перед вторым вызовом concat мы устанавливаем arr2[Symbol.isConcatSpreadable] значение в false, которое предотвращает распространение содержимого arr2 в новый массив, возвращаемый методом concat.

Symbol.iterator

Этот метод вызывается, когда мы хотим вернуть итератор для оператора распространения или цикла for...of. Он вызывается при запуске цикла for...of.

Например, учитывая, что у нас есть следующий код:

const obj = {
  0: 1,
  1: 2,
  2: 3
};
console.log(obj[0]);

Если вы попытаетесь перебрать массив с помощью цикла for...of или функции forEach или попытаться использовать оператор распространения с ним, пример с объектом obj приведет к ошибке, поскольку это не повторяемый объект.

Мы можем сделать его итеративным, добавив в него функцию генератора с символом Symbol.iterator, как показано в следующем коде:

const obj = {
  0: 1,
  1: 2,
  2: 3,
  [Symbol.iterator]: function*() {
    for (let prop in this) {
      yield this[prop];
    }
  }
};

Затем, когда мы повторяем объект obj с циклом for...of, как показано ниже:

for (let num of obj) {
  console.log(num);
}

Мы возвращаем записи нового объекта obj, которые мы сделали итеративными.

Оператор распространения также будет работать. Если у нас есть следующий код:

console.log([...obj]);

Получим [1, 2, 3]

Symbol.match

Логическое свойство, являющееся частью экземпляра регулярного выражения, которое заменяет соответствующую подстроку строки. Он вызывается методом replace.

Например, мы можем использовать его , чтобы позволить нам вызвать методы startsWith и endsWith с обычными строками:

const regexpFoo = /foo/;
regexpFoo[Symbol.match] = false;
console.log('/foo/'.startsWith(regexpFoo));
console.log('/baz/'.endsWith(regexpFoo));

Важной частью является то, что мы установили значение regexpFoo[Symbol.match] как false, которое указывает, что строка, с которой мы вызвали startsWith и endsWith не являются объектами регулярного выражения, поскольку проверка isRegExp укажет, что строки '/foo/' и '/baz/' не являются объектами регулярного выражения.

В противном случае они будут считаться объектами регулярного выражения, даже если они являются строками, и мы получим следующую ошибку:

Uncaught TypeError: First argument to String.prototype.startsWith must not be a regular expression

Symbol.replace

Метод регулярного выражения, который заменяет совпавшие подстроки строки. Вызывается методом String.prototype.replace.

Мы можем создать наш собственный метод replace для нашего объекта следующим образом, используя Symbol.replace в качестве идентификатора метода:

class Replacer {
  constructor(value) {
    this.value = value;
  }
  [Symbol.replace](string) {
    return this.value.replace(string, this.value);
  }
}
console.log('foo'.replace(new Replacer('bar')));

У класса Replacer есть конструктор, который принимает значение, которое можно использовать для замены текущего экземпляра строки.

Когда мы запускаем последнюю строку, мы должны получить ‘bar’, поскольку она имеет значение 'foo', и мы вызываем метод replace, чтобы заменить себя тем, что мы передали в конструктор Replacer.

Symbol.search

Метод регулярного выражения, который возвращает индекс в строке, соответствующей регулярному выражению. Вызывается по методу String.prototype.search.

Например, мы можем реализовать наш собственный метод Symbol.search, как в следующем коде:

class Searcher {
  constructor(value) {
    this.value = value;
  }
  [Symbol.search](string) {
    return string.indexOf(this.value) != -1;
  }
}
console.log('foobar'.search(new Searcher('bar')));

Мы получаем true из console.log, так как 'bar' находится в ‘foobar'. С другой стороны, если мы выполним:

console.log('foobar'.search(new Searcher('baz')));

Тогда мы получаем значение, false так как ‘baz’ нет в строке 'foobar'.

Symbol.species

Свойство, в качестве значения которого используется функция, являющаяся функцией конструктора, которая используется для создания производных объектов.

Symbol.split

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

Symbol.toPrimitive

Метод, который преобразует объект в соответствующее примитивное значение. Он вызывается, когда используется унарный оператор + или конвертирует объект в примитивную строку.

Например, мы можем написать наш собственный метод Symbol.toPrimitive для преобразования различных значений в примитивное значение:

let obj = {
    [Symbol.toPrimitive](hint) {
        if (hint == 'number') {
            return 10;
        }
        if (hint == 'string') {
            return 'hello';
        }
        if (hint == 'true') {
            return true;
        }
        if (hint == 'false') {
            return false;
        }
        return true;
    }
};
console.log(+obj);     
console.log(`${obj}`); 
console.log(!!obj);
console.log(!obj);

Тогда мы получим:

10
hello
true
false

Symbol.toString

Метод, который возвращает строковое представление объекта. Он вызывается всякий раз, когда вызывается метод объекта toString.

Symbol.unscopables

Объект, чьи собственные имена свойств являются именами свойств, которые исключены из привязок среды связанных объектов with.

Вывод

Символы - это новый тип данных, который был представлен в ES6. Они используются для идентификации свойств объекта. Они неизменны, и каждый экземпляр считается разным, даже если они имеют одинаковое содержание.

Мы можем реализовать различные методы, идентифицируемые специальными символами, для реализации определенных операций, таких как instanceof, преобразование объектов в примитивные значения и поиск подстрок в нашем собственном коде.

Источник:

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

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

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

Попробовать

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

Получить