Type String

String conversion

  • toString()Methods are visible in numeric, Boolean, object, and string values. The only purpose of this method is to return the string equivalent of the current value
    • Null and undefined have no toString() method
    • Numeric When you call this method, you can pass in a base number as an argument
let num = 10;
console.log(num.toString()); // "10" is in decimal by default
console.log(num.toString(2)); // "1010" binary
console.log(num.toString(8)); // "12" base 8
console.log(num.toString(10)); // "10" base 10
console.log(num.toString(16)); // "a" hexadecimal
Copy the code
  • String()Transformation function, the rules are as follows:
    • If the value has a toString() method, that method is called (with no arguments) and the result is returned
    • If the value is null, return “null”.
    • Return “undefined” if the value is undefined.

Template literals

  • ECMAScript 6 adds the ability to define strings using template literals
  • Unlike single or double quotation marks, template literals retain newline characters, strings can be defined across lines, and template strings support nesting without escaping
  • One of the most common features of template literals is support for string interpolation. Technically, a template literal is not a string, but a special JavaScript syntactic expression that evaluates to a string.
  • All inserted values are coerced into strings using toString(), and any JavaScript expression can be used for interpolation
console.log(`Hello, The ${`World` }! `);		// Hello, World!

let foo = { toString: () = > 'World' };
console.log(`Hello, ${ foo }! `);        // Hello, World!
Copy the code

Template literals tag functions

  • Template literals also support defining tag functions that allow you to customize the interpolation behavior.
  • The label function receives an array of strings delimited by interpolation tokens and evaluates each expression
let a = 6;
let b = 9;

function simpleTag(strings, aValExpression, bValExpression, sumExpression) {
 console.log(strings);
 console.log(aValExpression);
 console.log(bValExpression);
 console.log(sumExpression);
 return 'foobar';
}

let untaggedResult = `${ a } + ${ b } = ${ a + b }`;
let taggedResult = simpleTag`${ a } + ${ b } = ${ a + b }`;
// ["", " + ", " = ", "", raw: Array(4)]
/ / 6
/ / 9
/ / 15

console.log(untaggedResult); // "6 + 9 = 15"
console.log(taggedResult);   // "foobar"
Copy the code

Raw string

  • The defaultString.rawTag functions can retrieve the original template literal content (such as newlines or Unicode characters) rather than the converted character representation.
/ / Unicode example
// \u00A9 is a copyright symbol
console.log(`\u00A9`); / / ©
console.log(String.raw`\u00A9`); // \u00A9

// The newline example
console.log(`first line\nsecond line`);
// first line
// second line
console.log(String.raw`first line\nsecond line`); // "first line\nsecond line" 
Copy the code

Symbol type

Basic usage

  • Symbol is a new data type in ECMAScript 6
  • Symbols are primitive values, and symbol instances are unique and immutable
  • The purpose of the symbol is to ensure that object attributes are uniquely identified without the risk of attribute collisions
  • When we call the Symbol() function, we pass in a string argument as a description of the Symbol, which we can use to debug our code in the future. String arguments have nothing to do with symbol definitions or identifiers
let genericSymbol = Symbol(a);// Symbol()
let otherGenericSymbol = Symbol(a);let fooSymbol = Symbol('foo');  // Symbol(foo)
let otherFooSymbol = Symbol('foo');

console.log(genericSymbol == otherGenericSymbol); // false
console.log(fooSymbol == otherFooSymbol); // false
Copy the code
  • The Symbol() function cannot be used as a constructor with the new keyword
    • This is done to avoid creating symbolic wrapper objects like Boolean, String, or Number, which all support constructors and can be used to initialize wrapped objects that contain original values
let myBoolean = new Boolean(a);console.log(typeof myBoolean); // "object"

let myString = new String(a);console.log(typeof myString); // "object"

let myNumber = new Number(a);console.log(typeof myNumber); // "object"

let mySymbol = new Symbol(a);// TypeError: Symbol is not a constructor
Copy the code
  • If you want to wrap objects with symbols, you can also play this way
let mySymbol = Symbol(a);let myWrappedSymbol = Object(mySymbol);  // Symbol {Symbol()}

console.log(typeof myWrappedSymbol); // "object"
Copy the code

Global symbol registry

  • If different parts of the runtime need to share and reuse the Symbol instance, a string can be used as the key to passSymbol.for()Create and reuse symbols in the global symbol registry
  • Symbol.for() performs an idempotent operation on each string key
    • The method looks up the global runtime registry, creates a new symbol if no corresponding symbol instance exists and returns it if one already exists
  • Symbols defined in the global registry are used even if the same symbol description is usedSymbol()The symbols are defined differently
let fooGlobalSymbol = Symbol.for('foo');
console.log(typeof fooGlobalSymbol); // symbol

let fooGlobalSymbol = Symbol.for('foo'); // Create a new symbol
let otherFooGlobalSymbol = Symbol.for('foo'); // Reuse existing symbols
console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true 

let localSymbol = Symbol('foo');
let globalSymbol = Symbol.for('foo');
console.log(localSymbol === globalSymbol); // false
Copy the code
  • Symbol.keyFor()Method receives the symbol, queries the global registry, and returns the string key corresponding to the global symbol.
    • If the query is not global, undefined is returned
// Create a global symbol
let s = Symbol.for('foo');
console.log(Symbol.keyFor(s)); // foo

// Create a normal symbol
let s2 = Symbol('bar');
console.log(Symbol.keyFor(s2)); // undefined

// If the Symbol passed to symbol.keyfor () is not a Symbol, the method raises TypeError:
Symbol.keyFor(123); // TypeError: 123 is not a symbol
Copy the code

Use symbols as attributes

  • Wherever you can use strings or values as attributes, you can use symbols
    • That includesObject literal propertiesObject.defineProperties()Object.defineProperty()Defined properties
    • Object literals can only use symbols as attributes in the computed attribute syntax
let s1 = Symbol('foo'),
    s2 = Symbol('bar'),
    s3 = Symbol('baz'),
    s4 = Symbol('qux');

let o[s1] = 'foo val';
console.log(o);		// {Symbol(foo): foo val}


Object.defineProperty(o, s2, {value: 'bar val'});
console.log(o);		// {Symbol(foo): foo val, Symbol(bar): bar val}


Object.defineProperties(o, {
 [s3]: {value: 'baz val'},
 [s4]: {value: 'qux val'}});console.log(o);
// {Symbol(foo): foo val, Symbol(bar): bar val,
// Symbol(baz): baz val, Symbol(qux): qux val}
Copy the code
  • Object.getOwnPropertyNames()Returns an array of general properties of an object instance,Object.getOwnPropertySymbols()Returns an array of symbolic properties for an object instance.
    • The return values of these two methods are mutually exclusive
  • Object. GetOwnPropertyDescriptors () will return to contain both conventional and symbolic attributes descriptor Object
  • Reflect.ownkeys () returns two types of keys
let s1 = Symbol('foo'),
		s2 = Symbol('bar');

let o = {
 [s1]: 'foo val',
 [s2]: 'bar val'.baz: 'baz val'.qux: 'qux val'
};

console.log(Object.getOwnPropertySymbols(o));		// [Symbol(foo), Symbol(bar)]

console.log(Object.getOwnPropertyNames(o));		// ["baz", "qux"]

console.log(Object.getOwnPropertyDescriptors(o));		
// {baz: {... }, qux: {... }, Symbol(foo): {... }, Symbol(bar): {... }}

console.log(Reflect.ownKeys(o));
// ["baz", "qux", Symbol(foo), Symbol(bar)]
Copy the code

Commonly used built-in symbols

  • ECMAScript 6 also introduces a number of commonly used built-in symbols that expose language behavior that developers can directly access, rewrite, or emulate
  • Built-in symbols are usedSymbol factory functionExists in the form of a string attribute, which is the ordinary string attribute of the global function Symbol, pointing to an instance of a Symbol.
    • All built-in symbolic properties are not writable, enumerable, or configurable
  • One of the most important uses of these built-in symbols is to redefine them to change the behavior of native constructs

Symbol.iterator

  • This symbol represents, as a property, “a method that returns the default iterator for an object. Used by the for-of statement. In other words, this symbol represents the function that implements the iterator API.

  • Iterator, which by default returns an object that implements the iterator API. Usually, the object returned is a Generator that implements the API

class Foo {
  *[Symbol.iterator]() {}
}
let f = new Foo();
console.log(f[Symbol.iterator]());		// Generator {<suspended>} 
Copy the code
class Emitter {
  constructor(max) {
    this.max = max;
    this.idx = 0; } * [Symbol.iterator]() {
    while(this.idx < this.max) {
      yield this.idx++; }}}function count() {
  let emitter = new Emitter(5);

  for (const x of emitter) {
    console.log(x);
  }
}

count();
/ / 0
/ / 1
/ / 2
/ / 3
/ / 4
Copy the code

Symbol.asyncIterator

  • This symbol represents, as a property, “a method that returns the object’s default AsyncIterator.” Used by the for-await-of statement. In other words, this symbol represents a function that implements the asynchronous iterator API
class Emitter {
  constructor(max) {
    this.max = max;
    this.asyncIdx = 0;
  }

  async* [Symbol.asyncIterator]() {
    while (this.asyncIdx < this.max) {
      yield new Promise((resolve) = > {
        setTimeout(() = > {
          resolve(this.asyncIdx++)
        }, 1000)}); }}}function asyncCount() {
  let emitter = new Emitter(5);
  (async function () {
    for await (const x of emitter) {
      console.log(x);
    }
  })()

}

asyncCount(); // As you can guess, the result is serial printed
/ / 0
/ / 1
/ / 2
/ / 3
/ / 4
Copy the code

Symbol.hasInstance

  • This symbol represents, as a property, “a method that determines whether a constructor object recognizes an object as an instance of it. Used by the instanceof operator”
  • The instanceof operator can be used to determine whether an object instance has an archetype on its archetype chain
function Foo() {}
let f = new Foo();
console.log(f instanceof Foo); // true

class Bar {}
let b = new Bar();
console.log(b instanceof Bar); // true 
Copy the code
  • Alternatively, when instanceof is executed, the function with symbol.hasinstance as the key is called
function Foo() {}
let f = new Foo();
console.log(Foo[Symbol.hasInstance](f)); // true

class Bar {}
let b = new Bar();
console.log(Bar[Symbol.hasInstance](b)); // true
Copy the code
  • This property is defined on the prototype of Function, so it is called by default on all functions and classes.
    • Because the Instanceof operator looks for this property definition on the stereotype chain just as it would any other property on the stereotype chain, this function can be redefined statically on an inherited class
class Bar {}

class Baz extends Bar {
  static [Symbol.hasInstance]() {
    return false;  // Return false no matter what}}let b = new Baz();

console.log(Bar[Symbol.hasInstance](b)); // true

console.log(b instanceof Bar); // true

console.log(Baz[Symbol.hasInstance](b)); // false

console.log(b instanceof Baz); // false
Copy the code

Symbol.isConcatSpreadable

  • This symbol as an attribute means “a Boolean value, if true, which means the object should be flattened with array.prototype.concat () for its Array elements.”

  • The array.prototype.concat () method in ES6 selects how to concatenate an array-like object into an Array instance based on the type of object it receives. Cover Symbol isConcatSpreadable values can modify this behavior

    • The array objectBy default, it’s tied toExisting array.False or false valueCan lead toThe entire objectBe appended to theAt the end of the array
    • Array like objectBy default, it is appended toAt the end of the array.True, or true valueCan lead to thisArray like objectBe drawn toAn array of instance
    • The other is notArray like objectObjects, such as collection Set, the Symbol isConcatSpreadable is Set to true in the case will be ignored
let initial = ['foo'];
let array = ['bar'];

console.log(array[Symbol.isConcatSpreadable]); // The default is undefined
console.log(initial.concat(array)); // ['foo', 'bar']

array[Symbol.isConcatSpreadable] = false;
console.log(initial.concat(array)); // ['foo', Array(1)]

let arrayLikeObject = { length: 1.0: 'baz' }; // Class array object
console.log(arrayLikeObject[Symbol.isConcatSpreadable]); // undefined
console.log(initial.concat(arrayLikeObject)); // ['foo', {...}] is appended entirely to the end of the array by default

arrayLikeObject[Symbol.isConcatSpreadable] = true;
console.log(initial.concat(arrayLikeObject)); // ['foo', 'baz']

let otherObject = new Set().add('qux');
console.log(otherObject[Symbol.isConcatSpreadable]); // undefined
console.log(initial.concat(otherObject)); // ['foo', Set(1)]

otherObject[Symbol.isConcatSpreadable] = true;
console.log(initial.concat(otherObject)); // ['foo']
Copy the code

Symbol.match

  • This symbol represents, as a property, “a regular expression method that uses regular expressions to match strings. Used by the string.prototype.match () method”

  • Passing a non-regular expression value to the match method causes the value to be converted to a RegExp object

    • If you want to change this behavior so that the method uses parameters directly, you can redefine the symbol.match function to replace the default behavior of evaluating regular expressions, so that the match() method uses instances of non-regular expressions
    • The symbol.match function takes one argument, which is an instance of the string that calls the match() method
class FooMatcher {
  static [Symbol.match](target) {
    return target.includes('foo');  // Target is the string instance that calls the match method}}console.log('foobar'.match(FooMatcher)); // true
console.log('barbaz'.match(FooMatcher)); // false


class StringMatcher {
  constructor(str) {
    this.str = str;
  }
  
  [Symbol.match](target) {
    return target.includes(this.str);		// Target is the string instance that calls the match method}}console.log('foobar'.match(new StringMatcher('foo'))); // true
console.log('barbaz'.match(new StringMatcher('qux'))); // false
Copy the code

Symbol.replace

  • This symbol represents, as a property, “a regular expression method that replaces matched substrings in a string. Used by the string.prototype.replace () method”

  • Passing a non-regular expression value to the replace() method causes the value to be converted to a RegExp object

    • If you want to change this behavior and let methods use arguments directly, you can redefine the symbol.replace function to replace the default behavior of evaluating regular expressions, so that the replace() method uses non-regular expression instances
    • The symbol.replace function takes two arguments that call the replace() methodString instanceSubstitution string
class FooReplacer {
  static [Symbol.replace](target, replacement) {
    return target.split('foo').join(replacement); }}console.log('barfoobaz'.replace(FooReplacer, 'qux'));		// "barquxbaz"


class StringReplacer {
  constructor(str) {
    this.str = str;
  }
  
  [Symbol.replace](target, replacement) {
    return target.split(this.str).join(replacement); }}console.log('barfoobaz'.replace(new StringReplacer('foo'), 'qux'));		// "barquxbaz" 
Copy the code

Symbol.search

  • This symbol represents, as a property, “a regular expression method that returns an index in a string that matches a regular expression. Used by the string.prototype.search () method”

  • Passing a non-regular expression value to the search() method causes the value to be converted to a RegExp object

    • If you want to change this behavior and make methods use parameters directly, you can redefine the symbol.search function to replace the default behavior of evaluating regular expressions, thus making the search() method use instances of non-regular expressions
    • The symbol.search function takes an argument that is an instance of the string that calls the search() method
class FooSearcher {
  static [Symbol.search](target) {
    return target.indexOf('foo'); }}console.log('foobar'.search(FooSearcher)); / / 0
console.log('barfoo'.search(FooSearcher)); / / 3
console.log('barbaz'.search(FooSearcher)); // -1


class StringSearcher {
  constructor(str) {
    this.str = str;
  }
  
  [Symbol.search](target) {
    return target.indexOf(this.str); }}console.log('foobar'.search(new StringSearcher('foo'))); / / 0
console.log('barfoo'.search(new StringSearcher('foo'))); / / 3
console.log('barbaz'.search(new StringSearcher('qux'))); // -1 
Copy the code

Symbol.species

  • This symbol, as a property, represents “the value of a function used as a constructor to create a derived object.”
  • Use symbol.species to define static getter methods that override the stereotype definitions of newly created instances
class Bar extends Array {}

let bar = new Bar();
console.log(bar instanceof Array); // true
console.log(bar instanceof Bar); // true

bar = bar.concat('bar');
console.log(bar instanceof Array); // true
console.log(bar instanceof Bar); // true


class Baz extends Array {
  static get [Symbol.species]() {
    return Array; }}let baz = new Baz();
console.log(baz instanceof Array); // true
console.log(baz instanceof Baz); // true

baz = baz.concat('baz');
console.log(baz instanceof Array); // true
console.log(baz instanceof Baz); // false 
Copy the code

Symbol.split

  • This symbol represents, as a property, “a regular expression method that splits a string at the index that matches the regular expression. Used by string.prototype.split ()

  • Passing a non-regular expression value to split() causes the value to be converted to a RegExp object

    • If you want to change this behavior and let methods use arguments directly, you can redefine the symbol.split function to replace the default behavior of evaluating regular expressions, so that the split() method uses non-regular expression instances
    • The symbol.split function takes one argument, which is an instance of the string that calls the split() method
class FooSplitter {
  static [Symbol.split](target) {		// Target is the string instance that calls the split method
    return target.split('foo'); }}console.log('barfoobaz'.split(FooSplitter));		// ["bar", "baz"]

class StringSplitter {
  constructor(str) {
    this.str = str;
  }

  [Symbol.split](target) {
    return target.split(this.str); }}console.log('barfoobaz'.split(new StringSplitter('foo')));		// ["bar", "baz"] 
Copy the code

Symbol.toPrimitive

  • This symbol represents, as a property, “a method that converts an object to its corresponding original value. Used by ToPrimitive abstract operation”
  • Many built-in operations attempt to force an object to be converted to its original value, including strings, values, and unspecified primitive types
  • For a custom object instance, you can change the default behavior by defining a function on the symbol.toprimitive property of the instance that takes “string”, “number”, or “default”.
class Foo {}
let foo = new Foo();
console.log(3 + foo); // "3[object Object]"
console.log(3 - foo); // NaN
console.log(String(foo)); // "[object Object]"


class Bar {
  constructor() {
    this[Symbol.toPrimitive] = function(hint) {
      switch (hint) {
        case 'number':
          return 3;
        case 'string':
          return 'string bar';
        case 'default':
        default:
          return 'default bar'; }}}}let bar = new Bar();
console.log(3 + bar); // "3default bar" is not converted to the original string value
console.log(3 - bar); / / 0
console.log(String(bar)); // "string bar"	
Copy the code

Symbol.toStringTag

  • This symbol, as a property, represents “a string used to create the default string description of an object.” By the method of built-in Object. The prototype. The toString ()”

  • When the Object identifier is obtained through the toString() method, the instance identifier specified by symbol.toStringTag is retrieved, which defaults to “Object”.

    • The built-in types already specify this value, but custom class instances need to be explicitly defined
let s = new Set(a);console.log(s); // Set(0) {size: 0}
console.log(s.toString()); // [object Set]
console.log(s[Symbol.toStringTag]); // Set

class Foo {}
let foo = new Foo();
console.log(foo); // Foo {}
console.log(foo.toString()); // [object Object]
console.log(foo[Symbol.toStringTag]); // undefined

class Bar {
  constructor() {
    this[Symbol.toStringTag] = 'Bar'; }}let bar = new Bar();
console.log(bar); // Bar {Symbol(Symbol.toStringTag): 'Bar'}
console.log(bar.toString()); // [object Bar]
console.log(bar[Symbol.toStringTag]); // Bar 
Copy the code

The Object type

  • An object in ECMAScript is simply a collection of data and functionality
  • Object in ECMAScript is also a base class for deriving other objects
  • All properties and methods of type Object also exist on derived objects. Each Object instance has the following properties and methods:
    • Constructor: The function used to create the current object. The value of this property is the Object() function
    • HasOwnProperty (propertyName) : used to determine whether a given property exists on the current object instance (not the prototype). The propertyName to be checked must be a string or symbol
    • IsPrototypeOf (object) : Used to determine whether the current object is the prototype of another object
    • PropertyIsEnumerable (propertyName) : used to determine if a given property can be enumerated in a for-in statement. The propertyName must be a string
    • ToLocaleString () : Returns a string representation of an object that reflects its localized execution environment
    • ToString () : Returns a string representation of an object
    • ValueOf () : Returns a string, numeric, or Boolean representation of an object, usually the same as the value returned by toString()