• Symbol详解


    Symbol

    Symboles6引入的一个新的原始数据类型,是一个独一无二的值。
    目前为止,js的数据类型有以下几种:

    数据类型 说明
    undefined undefined
    null null
    boolean 布尔值
    string 字符串
    number 数字
    Bigint 大整数
    Object 对象
    Symbol Symbol

    Symbol通过Symbol()函数生成。对象的属性名现在除了可以使用字符串以外,还可以使用新增的Symbol类型。如果属性名使用Symbol,那么它就是独一无二的,不与其它属性名产生冲突。

    let s = Symbol()
    console.log(typeof s);  // symbol
    

    注意:Symbol()函数前不能使用new,否则报错。因为生成的Symbol是一个原始类型的值,而不是对象,所以不能使用new来调用。而且,Symbol值不是对象,不能给Symbol添加属性。可以这么理解,Symbol是一种类似于字符串的数据类型。

    Symbol接收字符串作为参数,表示对Symbol的描述,添加描述可以用来区分多个Symbol

    let s2 = Symbol('desc')
    let s3 = Symbol('desc2')
    console.log(s2);  // Symbol(desc)
    console.log(s3);  // Symbol(desc2)
    

    如果Symbol的参数传入的是对象,需要把对象转为字符串再生成Symbol,否则会显示[object Object]

    let obj = {
           name : '东方不败'
      }
    let s4 = Symbol(JSON.stringify(obj)) 
    console.log(s4); // Symbol({"name":"东方不败"})
    
    let s5 = Symbol(obj) 
    console.log(s5);// Symbol([object Object])
    

    Symbol传入的参数只是一个描述,实际上SymbolSymbol并不相等。

    let sy = Symbol()
    let sy2 = Symbol()
    console.log(sy === s2); // false
    
    let sy3 = Symbol('a')
    let sy4 = Symbol('a')
    console.log(sy3 === sy4); // false
    

    每调用一次Symbol()都会生成一个独一无二的值,每个Symbol都不相等。

    Symbol值不能参与其他类型值的运算,否则报错。

    let a = Symbol('hello')
    console.log(a + 'world');  // 报错 Cannot convert a Symbol value to a string
    

    Symbol转换

    Symbol可以转换为字符串

    let a2 = Symbol('hello')
    console.log(String(a2)); // Symbol(hello)
    

    如果需要返回Symbol的描述需要使用es2019提供的Symbol实例属性description返回描述。

    let a2 = Symbol('hello')
    console.log(a2.description); // hello
    

    Symbol可以转换为布尔值(boolean)

    let a2 = Symbol('hello')
    console.log(Boolean(a2));  // true
    console.log(Boolean(!a2)); // false
    

    Symbol属性名

    Symbol作为属性名

    let n = Symbol()
    // 方式一
    let obj2 = {
          [n] : '东方不败'
       }
    console.log(obj2);  // {Symbol(): '东方不败'}
    console.log(obj2[n]);  // 东方不败
    
    // 方式二
    obj2[n] = '东方求败'
    console.log(obj2[n]);  // 东方求败
    
    // 方式三
    let obj3 = {}
    let back = Object.defineProperty(obj3,n,{value : '艺术概论'})
    console.log(obj3[n]); // 艺术概论
    

    Object.defineProperty使用说明
    第一个参数:要在其上定义属性的对象
    第二个参数:要定义或修改的属性的名称
    第三个参数:将被定义或修改的属性描述符

    Symbol值作为对象属性名时,不能用点运算符获得Symbol属性,使用点运算符相当于是给对象添加了一个字符串属性名,而不是获取Symbol

    let n2 = Symbol()
    let obj4 = {}
    console.log(obj4.n2 = '中国工艺美术史');  // 中国工艺美术史
    console.log(obj4[n2]);  // undefined
    console.log(obj4);  // {n2: '中国工艺美术史'}
    

    属性名遍历

    Symbol是不可枚举的,Symbol作为对象键名时,是不可被遍历的,for...inObject.keys等方法都得不到Symbol键名,并且JSON.stringify()也不会返回Symbol

    let m = Symbol('a')
    let f = {
        [m]:'东方不败',
        name:'西方求败',
        name2: '光合作用'
    }
    
    // 西方求败 、 光合作用
    for(k in f){
       console.log(f[k]);
    }
    
    console.log(Object.keys(f)); // ['name','name2']
    console.log(JSON.stringify(f));  // {"name":"西方求败","name2":"光合作用"}
    

    Reflect.ownKeys()可以返回常规键名和Symbol键名

    console.log(Reflect.ownKeys(f)); //  ['name', 'name2', Symbol(a)] 
    

    Object.getOwnPropertySymbols()只返回Symbol属性

    console.log(Object.getOwnPropertySymbols(f)); // [Symbol(a)]
    

    Symbol.for()、Symbol.keyFor()

    Symbol.for()
    Symbol有一个特性就是Symbol不等于Sombol,但有时候我们需要同一个Symbol

    let r = Symbol.for('a')
    let r2 = Symbol.for('a')
    console.log(r === r2);  // true
    

    Symbol.for()Symbol()都会生成新的Symbol,前者会被登记在全局环境提供搜索,后者不会。
    Symbol.for()每次调用都会先检查参数key是否存在,如果不存在才会新建一个值。
    Symbol()每次调用都会新建一个值。

    Symbol.keyFor()
    Symbol.keyFor()返回已经登记的Symbol值的key

    let r3 = Symbol.for('b')
    let r4 = Symbol('c')
    console.log(Symbol.keyFor(r3));  // b
    console.log(Symbol.keyFor(r4));  // undefined
    

    Symbol内置值

    Symbol.hasInstance

    Symbol.hasInstance用来判断某个对象是否为某个构造器实例

    class myClass {
         static [Symbol.hasInstance](val){
                return typeof val === 'number'
         }
         // static [Symbol.hasInstance](val){
         //     return typeof val === 'boolean'
         // }
     }
    console.log(100 instanceof myClass); // true
    console.log('100' instanceof myClass); // false
    

    多个Symbol.hasInstance会覆盖,只保留最下面的那一个。


    Symbol.isConcatSpreadable

    Symbol.isConcatSpreadable用于表示Array.prototype.concat()是否可以展开,true、undefined可以展开,false不可展开。

    let arr1 = [1,2]
    let arr2 = [3,4]
    console.log(arr1[Symbol.isConcatSpreadable]);  // undefined
    console.log(arr1.concat(arr2));  // [1,2,3,4]
    

    在这里插入图片描述

    console.log(arr1[Symbol.isConcatSpreadable] = false)
    console.log(arr1.concat(arr2)); // [[1,2],3,4]
    

    在这里插入图片描述


    Symbol.species

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

    // 这里继承了Array的原型
    class MyArray extends Array { }
    let a = new MyArray(1,2,3)
    let b = a.map(el => el + 1)
    console.log(b);  // constructor : class MyArray
    

    在这里插入图片描述
    bc调用的是数组方法,那么应该是Array的实例,但实际上它们也是MyArray的实例

    class MyArray extends Array {
          static get [Symbol.species]() { return Array }
    }
    
    let a = new MyArray(1,2,3)
    let b = a.map(el => el + 1)
    let c = a.filter(el => el == 2)
    
    console.log(a,b,c);  // 1,2,3    2,3,4   2
    console.log(b instanceof MyArray); // false
    console.log(b);  // constructor : class MyArray
    

    在这里插入图片描述

    Symbol.species可以在创建衍生对象时使用这个属性返回的函数作为构造函数。
    这里returnArray,所以创建的衍生对象使用的Array作为构造函数,而不是MyArray
    如果这里return一个String,那么上面的map、filter会报错,因为衍生对象使用的是String作为构造函数,String是没有数组方法的。


    Symbol.match

    Symbol.match指向一个函数,如果函数存在则会被调用,并返回该方法的返回值

    class MyMatch {
          [Symbol.match](val){
             return 'hello world'.indexOf(val)
          }
    }
    
    // match字符串方法,可以在字符串内检索指定的值并返回
    console.log('e'.match(new MyMatch()));  // 1
    

    案例源码:https://gitee.com/wang_fan_w/es6-science-institute

    如果觉得这篇文章对你有帮助,欢迎点亮一下star哟

  • 相关阅读:
    【scikit-learn基础】--『监督学习』之 随机森林回归
    项目ERP与传统ERP的区别是什么?
    DETR精读笔记
    JS教程之 JavaScript 框架之战已经结束,而且只有一个赢家
    【Day31】力扣算法(超详细思路+注释)[1441. 用栈操作构建数组 ] [621. 任务调度器]
    严格反馈非线性系统基于事件触发的自抗扰预设有限时间跟踪控制
    文件的导出
    将vue项目变成可发布的npm包项目
    3D体验平台品牌应用——ENOVIA
    2023-10 字节跳动面试整个过程 golang营销服务开发岗位
  • 原文地址:https://www.cnblogs.com/wang-fan-w/p/17142933.html