Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

Today we will learn JavaScript’s new primitive type Symbol, we can use Symbol to create a unique value as an object attribute or value, we can also use Symbol’s well-known to modify the internal logic of JS language.

Create a Symbol

ES6 adds Symbol as the primitive data type, along with other primitive data types such as Number, Boolean, NULL, undefined, and String. Symbol has no literal form.

To create a symbol, we use the global function symbol ()

let s = Symbol('foo');
Copy the code

The Symbol() function creates a new unique value each time it is called

console.log(Symbol() = = =Symbol()); // false
Copy the code

The Symbol() function takes an optional parameter as a description to make Symbol more semantic.

Create two symbols: firstName and lastName.

let firstName = Symbol('first name'),
    lastName = Symbol('last name');
Copy the code

We implicitly call symbol’s toString() method when we use console.log() to print the symbol.

console.log(firstName); // Symbol(first name)
console.log(lastName); // Symbol(last name)
Copy the code

Since symbol is a primitive value, we can use typeof to check its type. Similarly, ES6 extends the Typeof keyword to return symbol when encountering a symbol type

console.log(typeof firstName); 
// symbol
Copy the code

Since it is a primitive type, it cannot be created using new

let s = new Symbol(a);// error
Copy the code

Shared symbol

To create a shared symbol, use the symbol.for () function instead of symbol ().

Symbol.for() also accepts an optional parameter as a description

let ssn = Symbol.for('ssn');
Copy the code

Symbol.for() first looks globally to see if there is a Symbol for the SSN already created, returns the Symbol already created if there is one, and creates a new Symbol if there is none.

Next, we create an identical symbol and then check that it is not the same symbol

let nz = Symbol.for('ssn');
console.log(ssn === nz); // true
Copy the code

Because the SSN symbol has been created above, the SYMBOL for the NZ variable will be the same as the symbol created above.

If you want to get the key of symbol, use the symbol.keyfor () method

console.log(Symbol.keyFor(nz)); // 'ssn'
Copy the code

Note that using symbol.keyfor () returns undefined if symbol is created through symbol ()

let systemID = Symbol('sys');
console.log(Symbol.keyFor(systemID)); // undefined
Copy the code

Symbol is futile

Use Symbol as a unique value

In code, we often use strings or numbers to represent some states, and we often face the problem of lack of semantics or repeated definition. In this case, using Symbol is the best choice. Each newly created Symbol is unique, and there will be no repetition.

In the example below, we use Symbol to represent several states of an order, rather than strings and numbers

let statuses = {
    OPEN: Symbol('Placed'),
    IN_PROGRESS: Symbol('In transit'),
    COMPLETED: Symbol('Order Fulfilled'),
    CANCELED: Symbol('Order Cancelled')};// Complete the order
task.setStatus(statuses.COMPLETED);
Copy the code

Use symbol as the object attribute

Use Symbol for the attribute name

let status = Symbol('status');

let task = {
    [status]: statuses.OPEN,
    description: 'Learn ES6 Symbol'
};

console.log(task);
Copy the code

Use object.keys () to get all the enumerable properties of an Object

console.log(Object.keys(task));
// ["description"]
Copy the code

Use Object. GetOwnPropertyNames () for all attributes, whether or not can be enumerated

console.log(Object.getOwnPropertyNames(task));
// ["description"]
Copy the code

To obtain Object Symbol of property, need to use new Object ES6. GetOwnPropertySymbols () method

console.log(Object.getOwnPropertySymbols(task));
//[Symbol(status)]
Copy the code

Well-known symbol

ES6 defines symbol-related attributes on the prototype chain to expose more of the language’s internal logic. Well-known symbols define functions for standard objects that were previously only visible within the language.

Symbol.hasInstance

Symbol.hasInstance is a Symbol that changes the default behavior of the instanceof operator, which is how we normally use instanceof

obj instanceof type;
Copy the code

The JavaScript then executes the symbol.hasintance method, as follows

type[Symbol.hasInstance](obj);
Copy the code

It calls the symbol.hasinstance static method of type, taking obj as an argument

class Stack {}console.log([] instanceof Stack);
// false
Copy the code

[] Array is not an instance of the Stack class, so return false.

Assuming we want the [] array to be an instance of the Stack class and return true, we can override the symbol.hasinstance method

class Stack {
    static [Symbol.hasInstance](obj) {
        return Array.isArray(obj); }}console.log([] instanceof Stack);
// true
Copy the code

Symbol.iterator

Symbol.iterator specifies whether the function returns an iterator of an object.

Objects with the Symbol. Iterator attribute are called iterables.

In ES6, Array, Set, Map, and String are all iterables.

ES6 provides for… The of loop, which can be used on an iterable.

var numbers = [1.2.3];
for (let num of numbers) {
    console.log(num);
}

/ / 1
/ / 2
/ / 3
Copy the code

Behind the scenes, the JavaScript engine first calls the symbol.iterator method of the numbers array to get the iterator object. It then calls iterator.next() and copies the iterator object’s value property into the num variable. After 3 iterations, The done object is true, and the loop rolls out.

We can get the iterator object of an array using symbol. iterator.

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}
Copy the code

By default, a self-defined collection is not iterable, but we can make it iterable using symbol. iterator

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

  add(element) {
    this.elements.push(element);
    return this; } * [Symbol.iterator]() {
    for (let element of this.elements) {
      yieldelement; }}}let chars = new List();
chars.add('A')
     .add('B')
     .add('C');

// Use Symbol. Iterator to implement iteration
for (let c of chars) {
  console.log(c);
}

// A
// B
// C
Copy the code

Symbol.isConcatSpreadable

We can combine two arrays using the concat() method

let odd  = [1.3],
    even = [2.4];
let all = odd.concat(even);
console.log(all); // [1, 3, 2, 4]
Copy the code

We can also use concat() to pass in individual elements instead of arrays

let extras = all.concat(5);
console.log(extras); // [1, 3, 2, 4, 5]
Copy the code

In the example above, when we pass an array to the concat() method, the concat() method expands the array into a single element. However, it treats individual raw parameters differently, and prior to ES6, we couldn’t change this behavior.

let list = {
    0: 'JavaScript'.1: 'Symbol'.length: 2
};
let message = ['Learning'].concat(list);
console.log(message); // ["Learning", Object]
Copy the code

The list object is merged into the [‘Learning’] array, but the individual elements of the list object are not merged into the array.

In concat () will list the elements in the object is added to the array of alone, we need to put the Symbol. IsConcatSpreadable attribute is added to the list object, like this

let list = {
    0: 'JavaScript'.1: 'Symbol'.length: 2[Symbol.isConcatSpreadable]: true
};
let message = ['Learning'].concat(list);
console.log(message); // ["Learning", "JavaScript", "Symbol"]
Copy the code

. If the Symbol isConcatSpreadable set to false, the concat () will list the entire object merge into the array.

Symbol.toPrimitive

The symbol.toprimitive method determines the behavior of an object when it is converted to its original value.

The JavaScript engine defines the symbol.toprimitive method on the prototype of each type value.

The symbol. toPrimitive method takes a hint parameter, which is string, number, and default. The hint parameter specifies the type of return value. Hint parameters are populated by the JavaScript engine based on the context in which the object is used.

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(10000.Renminbi);

console.log('I have' + price); // Price is 799USD
console.log(+price + 1); / / 800
console.log(String(price)); // 799USD
Copy the code

other

  • Symbol.match(regex) : A method called when the string.prototype.match () method is called to compare strings.

  • Symbol.replace(regex, replacement) : A method called when the string.prototype.replace () method is called to replace substrings of strings.

  • Symbol.search(regex) : A method called when the string.prototype.search () method is called to locate substrings in a String.

  • Symbol.species(regex) : Constructor used to create derived objects.

  • Symbol.split: a method called when the string.prototype.split () method is called to split strings.

  • Symbol. ToStringTag: a String in the call. The prototype. The toString () method is used when the String, used to create the object description.

  • Symbol.unscopables: A collection of objects that define the property names of objects that cannot be referenced by the with statement.

conclusion

Today, we learned all the ways of using Symbol, as well as some common ways in ordinary times. I hope it helps.

If this article is helpful, wechat search [xiaoshuai’s programming notes], let us progress every day