O guia definitivo para símbolos JavaScript

Resumo : neste tutorial, você aprenderá sobre o tipo primitivo de símbolo JavaScript e como usá-lo de maneira eficaz.

Criando símbolos

ES6 adicionado Symbolcomo um novo tipo primitivo. Ao contrário de outros tipos primitivos, como number , boolean , null , undefined e string , o tipo de símbolo não possui uma forma literal.

Para criar um novo símbolo, você usa a Symbol()função global conforme mostrado neste exemplo:

let s = Symbol('foo');Linguagem de código:  JavaScript  ( javascript )

A Symbol()função cria um novo valor exclusivo cada vez que você a chama:

console.log(Symbol() === Symbol()); // falseLinguagem de código:  JavaScript  ( javascript )

A Symbol()função aceita a descriptioncomo argumento opcional. O descriptionargumento tornará seu símbolo mais descritivo.

O exemplo a seguir cria dois símbolos: firstNamee lastName.

let firstName = Symbol('first name'),
    lastName = Symbol('last name');Linguagem de código:  JavaScript  ( javascript )

Você pode acessar a propriedade de descrição do símbolo usando o toString()método. O console.log()método chama o toString()método do símbolo implicitamente, conforme mostrado no exemplo a seguir:

console.log(firstName); // Symbol(first name)
console.log(lastName); // Symbol(last name)Linguagem de código:  JavaScript  ( javascript )

Como os símbolos são valores primitivos, você pode usar o   typeofoperador para verificar se uma variável é um símbolo. ES6 estendido  typeofpara retornar a symbolstring quando você passa uma variável de símbolo:

console.log(typeof firstName); // symbolLinguagem de código:  JavaScript  ( javascript )

Como um símbolo é um valor primitivo, se você tentar criar um símbolo usando o newoperador, receberá um erro:

let s = new Symbol(); // errorLinguagem de código:  JavaScript  ( javascript )

Compartilhando símbolos

ES6 fornece um registro de símbolos global que permite compartilhar símbolos globalmente. Se você deseja criar um símbolo que será compartilhado, use o Symbol.for()método em vez de chamar a Symbol()função.

O Symbol.for()método aceita um único parâmetro que pode ser utilizado para descrição do símbolo, conforme exemplo a seguir:

let ssn = Symbol.for('ssn');Linguagem de código:  JavaScript  ( javascript )

O Symbol.for()método primeiro procura o símbolo com a   ssnchave no registro global de símbolos. Ele retorna o símbolo existente, se houver. Caso contrário, o Symbol.for()método cria um novo símbolo, registra-o no registro global de símbolos com a chave especificada e retorna o símbolo.

Posteriormente, se você chamar o Symbol.for()método usando a mesma chave, o Symbol.for()método retornará o símbolo existente.

let citizenID = Symbol.for('ssn');
console.log(ssn === citizenID); // trueLinguagem de código:  JavaScript  ( javascript )

Neste exemplo, usamos o Symbol.for()método para procurar o símbolo com a   ssnchave. Como o registro global de símbolos já o continha, o Symbol.for()método retornou o símbolo existente.

Para obter a chave associada a um símbolo, você usa o Symbol.keyFor()método mostrado no exemplo a seguir:

console.log(Symbol.keyFor(citizenID)); // 'ssn'Linguagem de código:  JavaScript  ( javascript )

Se um símbolo não existir no registro global de símbolos, o System.keyFor()método retornará undefined.

let systemID = Symbol('sys');
console.log(Symbol.keyFor(systemID)); // undefinedLinguagem de código:  JavaScript  ( javascript )

Usos de símbolos

A) Usando símbolos como valores únicos

Sempre que você usar uma string ou um número em seu código, você deve usar símbolos. Por exemplo, você precisa gerenciar o status no aplicativo de gerenciamento de tarefas.

Antes do ES6, você usaria strings como open, in progress, completed, cancelede on holdpara representar diferentes status de uma tarefa. No ES6, você pode usar símbolos da seguinte forma:

let statuses = {
    OPEN: Symbol('Open'),
    IN_PROGRESS: Symbol('In progress'),
    COMPLETED: Symbol('Completed'),
    HOLD: Symbol('On hold'),
    CANCELED: Symbol('Canceled')
};
// complete a task
task.setStatus(statuses.COMPLETED);
Linguagem de código:  JavaScript  ( javascript )

B) Usando um símbolo como o nome da propriedade computada de um objeto

Você pode usar símbolos como nomes de propriedades computadas . Veja o exemplo a seguir:

let status = Symbol('status');
let task = {
    [status]: statuses.OPEN,
    description: 'Learn ES6 Symbol'
};
console.log(task);Linguagem de código:  JavaScript  ( javascript )

Para obter todas as propriedades enumeráveis ​​de um objeto, você usa o Object.keys()método.

console.log(Object.keys(task)); // ["description"]Linguagem de código:  JavaScript  ( javascript )

Para obter todas as propriedades de um objeto, sejam elas enumeráveis ​​ou não, você usa o Object.getOwnPropertyNames()método.

console.log(Object.getOwnPropertyNames(task)); // ["description"]Linguagem de código:  JavaScript  ( javascript )

Para obter todos os símbolos de propriedades de um objeto, você usa o Object.getOwnPropertySymbols()método, que foi adicionado no ES6.

console.log(Object.getOwnPropertySymbols(task)); //[Symbol(status)]Linguagem de código:  JavaScript  ( javascript )

O Object.getOwnPropertySymbols()método retorna uma matriz de símbolos de propriedades próprias de um objeto.

Símbolos conhecidos

ES6 fornece símbolos predefinidos que são chamados de símbolos bem conhecidos. Os símbolos conhecidos representam os comportamentos comuns em JavaScript. Cada símbolo conhecido é uma propriedade estática do Symbolobjeto.

Símbolo.hasInstance

O Symbol.hasInstanceé um símbolo que altera o comportamento do instanceofoperador. Normalmente, quando você usa o instanceofoperador:

obj instanceof type;Linguagem de código:  JavaScript  ( javascript )

JavaScript chamará o Symbol.hasIntancemétodo da seguinte maneira:

type[Symbol.hasInstance](obj);Linguagem de código:  JavaScript  ( javascript )

Depende então do método para determinar se  objé uma instância do typeobjeto. Veja o exemplo a seguir.

class Stack {
}
console.log([] instanceof Stack); // false
Linguagem de código:  JavaScript  ( javascript )

O []array não é uma instância da Stackclasse, portanto, o instanceofoperador retorna falseneste exemplo.

Supondo que você queira que o []array seja uma instância da Stackclasse, você pode adicionar o Symbol.hasInstancemétodo da seguinte forma:

class Stack {
    static [Symbol.hasInstance](obj) {
        return Array.isArray(obj);
    }
}
console.log([] instanceof Stack); // true
Linguagem de código:  JavaScript  ( javascript )

Símbolo.iterador

Especifica Symbol.iteratorse uma função retornará um iterador para um objeto.

Os objetos que possuem Symbol.iteratorpropriedade são chamados de objetos iteráveis.

No ES6, todos os objetos de coleção (A rray , Set e Map ) e strings são objetos iteráveis.

ES6 fornece o loop for…of que funciona com o objeto iterável como no exemplo a seguir.

var numbers = [1, 2, 3];
for (let num of numbers) {
    console.log(num);
}

// 1
// 2
// 3Linguagem de código:  JavaScript  ( javascript )

Internamente, o mecanismo JavaScript primeiro chama o Symbol.iteratormétodo do array de números para obter o objeto iterador.

Em seguida, ele invoca o iterator.next()método e copia a propriedade value do objeto iterador para a num variável.

Após três iterações, a donepropriedade do objeto de resultado é true, o loop termina.

Você pode acessar o objeto iterador padrão via System.iteratorsímbolo da seguinte forma:

var iterator = numbers[Symbol.iterator]();

console.log(iterator.next()); // Object {value: 1, done: false}
console.log(iterator.next()); // Object {value: 2, done: false}
console.log(iterator.next()); // Object {value: 3, done: false}
console.log(iterator.next()); // Object {value: undefined, done: true}Linguagem de código:  JavaScript  ( javascript )

Por padrão, uma coleção não é iterável. No entanto, você pode torná-lo iterável usando Symbol.iteratorconforme mostrado no exemplo a seguir:

class List {
    constructor() {
        this.elements = [];
    }

    add(element) {
        this.elements.push(element);
        return this;
    }

    *[Symbol.iterator]() {
        for (let element of this.elements) {
            yield  element;
        }
    }
}

let chars = new List();
chars.add('A')
     .add('B')
     .add('C');

// because of the Symbol.iterator
for (let c of chars) {
    console.log(c);
}

// A
// B
// CLinguagem de código:  JavaScript  ( javascript )

Símbolo.isConcatSpreadable

Para concatenar dois arrays, você usa o concat()método mostrado no exemplo a seguir:

let odd  = [1, 3],
    even = [2, 4];
let all = odd.concat(even);
console.log(all); // [1, 3, 2, 4]Linguagem de código:  JavaScript  ( javascript )

Neste exemplo, a matriz resultante contém os elementos únicos de ambas as matrizes. Além disso, o concat()método também aceita um argumento que não seja de array, conforme ilustrado abaixo.

let extras = all.concat(5);
console.log(extras); // [1, 3, 2, 4, 5]Linguagem de código:  JavaScript  ( javascript )

O número 5 se torna o quinto elemento da matriz.

Como você pode ver no exemplo acima, quando passamos um array para o concat()método, o concat()método espalha o array em elementos individuais. No entanto, trata um único argumento primitivo de forma diferente. Antes do ES6, não era possível alterar esse comportamento.

É por isso que o Symbol.isConcatSpreadablesímbolo entra em jogo.

A Symbol.isConcatSpreadablepropriedade é um valor booleano que determina se um objeto é adicionado individualmente ao resultado da concat()função.

Considere o seguinte exemplo:

let list = {
    0: 'JavaScript',
    1: 'Symbol',
    length: 2
};
let message = ['Learning'].concat(list);
console.log(message); // ["Learning", Object]Linguagem de código:  JavaScript  ( javascript )

O objeto de lista é concatenado ao ['Learning']array. No entanto, os seus elementos individuais não estão dispersos.

Para habilitar os elementos do listobjeto adicionados ao array individualmente ao passar para o concat()método, você precisa adicionar a Symbol.isConcatSpreadablepropriedade ao listobjeto da seguinte forma:

let list = {
    0: 'JavaScript',
    1: 'Symbol',
    length: 2,
    [Symbol.isConcatSpreadable]: true
};
let message = ['Learning'].concat(list);
console.log(message); // ["Learning", "JavaScript", "Symbol"]Linguagem de código:  JavaScript  ( javascript )

Observe que se você definir o valor de Symbol.isConcatSpreadableto falsee passar o listobjeto para o concat()método, ele será concatenado ao array como o objeto inteiro.

Símbolo.toPrimitivo

O Symbol.toPrimitivemétodo determina o que deve acontecer quando um objeto é convertido em um valor primitivo.

O mecanismo JavaScript define o Symbol.toPrimitivemétodo no protótipo de cada tipo padrão.

O Symbol.toPrimitivemétodo aceita um hintargumento que possui um de três valores: “número”, “string” e “padrão”. O hintargumento especifica o tipo do valor de retorno. O hintparâmetro é preenchido pelo mecanismo JavaScript com base no contexto em que o objeto é utilizado.

Aqui está um exemplo de uso do Symbol.toPrimitivemétodo.

function Money(amount, currency) {
    this.amount = amount;
    this.currency = currency;
}
Money.prototype[Symbol.toPrimitive] = function(hint) {
    var result;
    switch (hint) {
        case 'string':
            result = this.amount + this.currency;
            break;
        case 'number':
            result = this.amount;
            break;
        case 'default':
            result = this.amount + this.currency;
            break;
    }
    return result;
}

var price = new Money(799, 'USD');

console.log('Price is ' + price); // Price is 799USD
console.log(+price + 1); // 800
console.log(String(price)); // 799USDLinguagem de código:  JavaScript  ( javascript )

Neste tutorial, você aprendeu sobre símbolos JavaScript e como usar símbolos para valores exclusivos e propriedades de objetos. Além disso, você aprendeu como usar símbolos conhecidos para modificar o comportamento dos objetos.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *