• 7.新增类型Symbol


    1.Symbol简介


    Symbol是ES6新增的数据类型,由Symbol函数生成,表示独一无二的值,属于简单数据类型,通常用于定义属性名,以保证不与其他属性名产生冲突

    let s1 = Symbol('jack') // Symbol(jack)
    let s2 = Symbol('jack') // Symbol(jack)
    
    s1 === s2 // false,独一无二
    
    • 1
    • 2
    • 3
    • 4

    创建Symbol时,传入的参数会成为它的description属性

    const sym = Symbol('jack')
    sym.description  // jack
    
    • 1
    • 2

    2.Symbol属性读写


    Symbol类型作为属性读写需要使用形如[symbol]的方式

    let sym = Symbol()
    let fn = Symbol('fn of Symbol')
    
    let a = {
      [sym]: 'Hello!',
      [fn](){
        alert(this[sym])
      }
    };
    // 或者
    let a = {}
    Object.defineProperty(a, sym, { value: 'Hello!'})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    访问时不能通过点运算符

    let sym = Symbol()
    let a = {}
    a[sym] = 'jack'
    a.sym = 'tom' // 点操作符读取的不是Symbol类型的sym,而是普通字符串sym
    console.log(a[sym]) // jack
    console.log(a.sym) // tom
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    通过Symbol类型可以定义一组常量,以保证唯一性

    const COLOR_RED = Symbol()
    const COLOR_GREEN = Symbol()
    
    function getComplement(color) {
      switch (color) {
        case COLOR_RED:   // 仅匹配唯一的COLOR_RED
          return COLOR_GREEN
        case COLOR_GREEN:
          return COLOR_RED
        default:
          throw new Error('Undefined color');
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.Symbol属性遍历


    Symbol属性只能通过Object.getOwnPropertySymbols()方法遍历,
    不能被for-infor-ofObject.keys()Object.getOwnPropertyNames()JSON.stringify()遍历读取

    const name = Symbol('name')
    const obj = {
      Symbol('id'): 1007
    }
    obj[name] = 'jack'
    
    for(let i in obj){
      console.log(i) // 无输出
    }
    let propertySymArr = Object.getOwnPropertySymbols(obj) // [Symbol(id), Symbol(name)]
    
    for(let i in propertySymArr){
      console.log(obj[propertySymArr[i]]) // 1007, jack
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    另外,Reflect.ownKeys(obj)可以返回包含常规键名Symbol键名的数组

    4.Symbol定义私有属性


    利用symbol属性名不能被常规方法遍历到的这一特性,可以将定义私有的属性

      let size = Symbol('size')
      class Collection {
        constructor() {
          this[size] = 0 // 私有
        }
        add(item) {
          this[this[size]] = item // 妙啊~ 
          this[size]++
        }
        static sizeOf(instance) {
          return instance[size]
        }
      }
    
      let x = new Collection()
    
      x.add('foo')
      Collection.sizeOf(x) // 1
      x[0] // 'foo'
      Collection.sizeOf(x) // 0
      
      Object.keys(x) // ['0']
      Object.getOwnPropertyNames(x) // ['0']
      Object.getOwnPropertySymbols(x) // [Symbol(size)]
      Reflect.ownKeys(x) // ['0',Symbol(size)]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    5.Symbol.for()和Symbol.keyFor()


    Symbol.for(str)返回descriptionstr的symbol变量,若没有则在全局注册一个
    不多bb直接甩代码

    let s1 = Symbol.for('foo') // 没有description属性为'foo'的symbol变量,全局注册一个 Symbol('foo')
    let s2 = Symbol.for('foo') // 返回Symbol('foo')
    
    s1 === s2 // true
    
    • 1
    • 2
    • 3
    • 4

    Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key,若没有则返回undefined

    let s1 = Symbol.for('foo') // 注意,这里将会在全局注册
    Symbol.keyfor(s1) // foo
    
    let s2 = Symbol('foo') // 没在全局注册
    Symbol.keyfor(s2) // undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5

    6.Symbol应用于Singleton模式

    Singleton模式指的是调用一个类,任何时候返回的都是同一个实例,对于Node保证的是每次执行一个模块文件,返回的都是同一个实例,其核心思想是将实例放到顶层对象global作为属性存在
    以下是不使用Symbol的情况:

    // mod.js
    function A(){
      this.name = 'jack'
    }
    if(!global._a){
      global._a = new A()
    }
    module.exports = global._a
    
    
    // index1.js
    const a = require('./mod.js')
    
    // index2.js 
    const b = requre('./mod.js')
    
    // a和b都应用同一个A类实例
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    问题在于,如果有个坏蛋在一个文件上修改了global._a,其他后面文件再引入global._a就GG了,那么可以用Symbol的唯一性和私用化属性这一特性了

    const A_KEY = Symbol('a') // 局部注册,而非全局注册
    
    function A() {
      this.a = 'hello'
    }
    
    if (!global[A_KEY]) {
      global[A_KEY] = new A()
    }
    
    module.exports = global[A_KEY]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    // index3.js,写这个文件的小坏蛋想尝试修改global[A_KEY]
    global[A_KEY] = {a: 'haha~'} // 抱歉,你没有这个[A_KEY]
    global[Symbol('a')] = {a: '我再来'} //抱歉,symbol是唯一的,你这个Symbol('a') 与我的Symbol('a') 不是同一个
    
    • 1
    • 2
    • 3

    7.全局内置Symbol值


    7.1 [Symbol.hasInstance]

    可以用于重写instanceof机制,当执行 instanceof 操作符时,会在构造器内部调用这个方法

     a instanceof A// 实际调用A[Symbol.hasInstance](a)
    
    • 1

    举个例子

    class Person{
      [Symbol.hasInstance](obj){
        return obj instanceof Array
      }
    }
    [1,2,3] instanceof new Person // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    7.2 [Symbol.isConcatSpreadable]

    [Symbol.isConcatSpreadable]是一个布尔值,当指向 Array.prototype.concat()时,决定其是否可以展开

      let arr1 = [1,2]
      let res = [3,4].concat(arr1, 5) // [3,4,1,2,5]
    
      let arr2 = [1,2]
      arr2[Symbol.isConcatSpreadable] = false // 关闭展开机制
      let res = [3,4].concat(arr2, 5) // [3,4,[1,2],5]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    若想将一个伪数组的对象展开,可以指定[Symbol.isConcatSpreadable]为true

    let obj = {length: 2, 0: 'c', 1: 'd'}
    
    obj[Symbol.isConcatSpreadable] = true
    ['a', 'b'].concat(obj, 'e') // ['a', 'b', 'c', 'd', 'e']
    
    • 1
    • 2
    • 3
    • 4
    ☆7.3 [Symbol.iterator]

    指向对象的默认遍历器方法

    const myIterable = {};
    myIterable[Symbol.iterator] = function* () {
      yield 1
      yield 2
      yield 3
    };
    
    [...myIterable] // [1, 2, 3]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    class Collection {
      *[Symbol.iterator]() {
        let i = 0;
        while(this[i] !== undefined) {
          yield this[i]
          ++i;
        }
      }
    }
    
    let myCollection = new Collection()
    myCollection[0] = 1
    myCollection[1] = 2
    
    for(let value of myCollection) {
      console.log(value) // 1、2
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    Liunx 重置MySQL用户密码
    举例解释大数定律、中心极限定理及其在机器学习中的应用
    R语言ggplot2可视化:使用ggcharts包的pyramid_chart函数可视化人口金字塔图(pyramid chart)
    Ocelot使用与设置路由Routing
    前端收集(bootstrap,html,vue等)
    编译概念总结
    vue锚点链接
    UE4 回合游戏项目 06- 战斗场景-返回之前的位置
    Android 14 Beta 1
    axios 取消请求:CancelToken
  • 原文地址:https://blog.csdn.net/Xiaoyc7/article/details/125531534