zoukankan      html  css  js  c++  java
  • ES6知识点整理之----Symbol

    1、ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。注意,Symbol函数前不能使用new命令,否则会报错。由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。

    现在ES6一共有7种原始数据类型:undefinednull、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)以及Symbol。

    let s = Symbol();
    
    typeof s
    // "symbol"

    Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。

    let s1 = Symbol('foo');
    let s2 = Symbol('bar');
    
    s1 // Symbol(foo)
    s2 // Symbol(bar)
    
    s1.toString() // "Symbol(foo)"
    s2.toString() // "Symbol(bar)"

    如果 Symbol 的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,然后才生成一个 Symbol 值。

    const obj = {
      toString() {
        return 'abc';
      }
    };
    const sym = Symbol(obj);
    sym // Symbol(abc)

    注意,Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。

    // 没有参数的情况
    let s1 = Symbol();
    let s2 = Symbol();
    
    s1 === s2 // false
    
    // 有参数的情况
    let s1 = Symbol('foo');
    let s2 = Symbol('foo');
    
    s1 === s2 // false

    Symbol 值不能与其他类型的值进行运算,会报错。Symbol 值可以显式转为字符串。Symbol 值也可以转为布尔值,但是不能转为数值。

    2、由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。

    let mySymbol = Symbol();
    
    // 第一种写法
    let a = {};
    a[mySymbol] = 'Hello!';
    
    // 第二种写法
    let a = {
      [mySymbol]: 'Hello!'
    };
    
    // 第三种写法
    let a = {};
    Object.defineProperty(a, mySymbol, { value: 'Hello!' });
    
    // 以上写法都得到同样结果
    a[mySymbol] // "Hello!"

    Symbol 值作为对象属性名时,不能用点运算符。在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。Symbol 类型还可以用于定义一组常量,保证这组常量的值都是不相等的。Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。

    3、Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

    const obj = {};
    let a = Symbol('a');
    let b = Symbol('b');
    
    obj[a] = 'Hello';
    obj[b] = 'World';
    
    const objectSymbols = Object.getOwnPropertySymbols(obj);
    
    objectSymbols
    // [Symbol(a), Symbol(b)]

    另一个新的 API,Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。

    let obj = {
      [Symbol('my_key')]: 1,
      enum: 2,
      nonEnum: 3
    };
    
    Reflect.ownKeys(obj)
    //  ["enum", "nonEnum", Symbol(my_key)]

    Symbol.for(),Symbol.keyFor()

    Symbol.for方法重新使用同一个 Symbol 值,接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。

    let s1 = Symbol.for('foo');
    let s2 = Symbol.for('foo');
    
    s1 === s2 // true

    Symbol.for()Symbol()这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for为 Symbol 值登记的名字,是全局环境的,可以在不同的 iframe 或 service worker 中取到同一个值。

    Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key

    let s1 = Symbol.for("foo");
    Symbol.keyFor(s1) // "foo"
    
    let s2 = Symbol("foo");
    Symbol.keyFor(s2) // undefined

    Symbol可以使用在模块的Singleton模式中。

    内置的 Symbol 值

    Symbol.hasInstance

    对象的Symbol.hasInstance属性,指向一个内部方法。当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。

    class MyClass {
      [Symbol.hasInstance](foo) {
        return foo instanceof Array;
      }
    }
    
    [1, 2, 3] instanceof new MyClass() // true

    Symbol.isConcatSpreadable

    对象的Symbol.isConcatSpreadable属性等于一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开。

    let arr1 = ['c', 'd'];
    ['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
    arr1[Symbol.isConcatSpreadable] // undefined
    
    let arr2 = ['c', 'd'];
    arr2[Symbol.isConcatSpreadable] = false;
    ['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']

    类似数组的对象正好相反,默认不展开。它的Symbol.isConcatSpreadable属性设为true,才可以展开。

    let obj = {length: 2, 0: 'c', 1: 'd'};
    ['a', 'b'].concat(obj, 'e') // ['a', 'b', obj, 'e']
    
    obj[Symbol.isConcatSpreadable] = true;
    ['a', 'b'].concat(obj, 'e') // ['a', 'b', 'c', 'd', 'e']

    Symbol.species

    对象的Symbol.species属性,指向一个构造函数。创建衍生对象时,会使用该属性。

    class MyArray extends Array {
    }
    
    const a = new MyArray(1, 2, 3);     //a是MyArray的实例
    const b = a.map(x => x);            //b是a的衍生对象
    const c = a.filter(x => x > 1);     //c是a的衍生对象
    
    b instanceof MyArray // true
    c instanceof MyArray // true

    使用了Symbol.species属性后,定义Symbol.species属性要采用get取值器,如下例子:

    class MyArray extends Array {
      static get [Symbol.species]() { return Array; }
    }
    
    const a = new MyArray();
    const b = a.map(x => x);
    
    b instanceof MyArray // false
    b instanceof Array // true

    Symbol.match

    对象的Symbol.match属性,指向一个函数。当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值。

    String.prototype.match(regexp)
    // 等同于
    regexp[Symbol.match](this)
    
    class MyMatcher {
      [Symbol.match](string) {
        return 'hello world'.indexOf(string);
      }
    }
    
    'e'.match(new MyMatcher()) // 1

    Symbol.replace

    对象的Symbol.replace属性,指向一个方法,当该对象被String.prototype.replace方法调用时,会返回该方法的返回值。

    String.prototype.replace(searchValue, replaceValue)
    // 等同于
    searchValue[Symbol.replace](this, replaceValue)

    对象的Symbol.search属性,指向一个方法,当该对象被String.prototype.search方法调用时,会返回该方法的返回值。

    String.prototype.search(regexp)
    // 等同于
    regexp[Symbol.search](this)
    
    class MySearch {
      constructor(value) {
        this.value = value;
      }
      [Symbol.search](string) {
        return string.indexOf(this.value);
      }
    }
    'foobar'.search(new MySearch('foo')) // 0

    Symbol.split

    对象的Symbol.split属性,指向一个方法,当该对象被String.prototype.split方法调用时,会返回该方法的返回值。

    String.prototype.split(separator, limit)
    // 等同于
    separator[Symbol.split](this, limit)

    Symbol.iterator

    对象的Symbol.iterator属性,指向该对象的默认遍历器方法。

    const myIterable = {};
    myIterable[Symbol.iterator] = function* () {
      yield 1;
      yield 2;
      yield 3;
    };
    
    [...myIterable] // [1, 2, 3]

    Symbol.toPrimitive

    对象的Symbol.toPrimitive属性,指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。

    Symbol.toPrimitive被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式。

    • Number:该场合需要转成数值
    • String:该场合需要转成字符串
    • Default:该场合可以转成数值,也可以转成字符串
    let obj = {
      [Symbol.toPrimitive](hint) {
        switch (hint) {
          case 'number':
            return 123;
          case 'string':
            return 'str';
          case 'default':
            return 'default';
          default:
            throw new Error();
         }
       }
    };
    
    2 * obj // 246
    3 + obj // '3default'
    obj == 'default' // true
    String(obj) // 'str'

    Symbol.toStringTag

    对象的Symbol.toStringTag属性,指向一个方法。在该对象上面调用Object.prototype.toString方法时,如果这个属性存在,它的返回值会出现在toString方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制[object Object][object Array]object后面的那个字符串。

    // 例一
    ({[Symbol.toStringTag]: 'Foo'}.toString())
    // "[object Foo]"
    
    // 例二
    class Collection {
      get [Symbol.toStringTag]() {
        return 'xxx';
      }
    }
    let x = new Collection();
    Object.prototype.toString.call(x) // "[object xxx]"

    ES6 新增内置对象的Symbol.toStringTag属性值如下。

    • JSON[Symbol.toStringTag]:'JSON'
    • Math[Symbol.toStringTag]:'Math'
    • Module 对象M[Symbol.toStringTag]:'Module'
    • ArrayBuffer.prototype[Symbol.toStringTag]:'ArrayBuffer'
    • DataView.prototype[Symbol.toStringTag]:'DataView'
    • Map.prototype[Symbol.toStringTag]:'Map'
    • Promise.prototype[Symbol.toStringTag]:'Promise'
    • Set.prototype[Symbol.toStringTag]:'Set'
    • %TypedArray%.prototype[Symbol.toStringTag]:'Uint8Array'等
    • WeakMap.prototype[Symbol.toStringTag]:'WeakMap'
    • WeakSet.prototype[Symbol.toStringTag]:'WeakSet'
    • %MapIteratorPrototype%[Symbol.toStringTag]:'Map Iterator'
    • %SetIteratorPrototype%[Symbol.toStringTag]:'Set Iterator'
    • %StringIteratorPrototype%[Symbol.toStringTag]:'String Iterator'
    • Symbol.prototype[Symbol.toStringTag]:'Symbol'
    • Generator.prototype[Symbol.toStringTag]:'Generator'
    • GeneratorFunction.prototype[Symbol.toStringTag]:'GeneratorFunction'

    Symbol.unscopables

    对象的Symbol.unscopables属性,指向一个对象。该对象指定了使用with关键字时,哪些属性会被with环境排除。

    Array.prototype[Symbol.unscopables]
    // {
    //   copyWithin: true,
    //   entries: true,
    //   fill: true,
    //   find: true,
    //   findIndex: true,
    //   includes: true,
    //   keys: true
    // }
    
    Object.keys(Array.prototype[Symbol.unscopables])
    // ['copyWithin', 'entries', 'fill', 'find', 'findIndex', 'includes', 'keys']
    //代码说明,数组有 7 个属性,会被with命令排除。
  • 相关阅读:
    bzoj1415 NOI2005聪聪和可可
    Tyvj1952 Easy
    poj2096 Collecting Bugs
    COGS 1489玩纸牌
    COGS1487 麻球繁衍
    cf 261B.Maxim and Restaurant
    cf 223B.Two Strings
    cf 609E.Minimum spanning tree for each edge
    cf 187B.AlgoRace
    cf 760B.Frodo and pillows
  • 原文地址:https://www.cnblogs.com/adhehe/p/9668137.html
Copyright © 2011-2022 走看看