搜索

查看: 3196|回复: 11

[JavaScript] 详解JavaScript中原始数据类型Symbol的使用

[复制链接]
发表于 2023-5-4 11:51:43 | 显示全部楼层 |阅读模式
Editor 2023-5-4 11:51:43 3196 11 看全部
目录
  • Symbol
  • Symbol转换
  • Symbol属性名
  • 属性名遍历
  • Symbol.for()、Symbol.keyFor()
  • Symbol内置值
  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.species
  • Symbol.match
    Symbol
    Symbol是es6引入的一个新的原始数据类型,是一个独一无二的值。
    目前为止,js的数据类型有以下几种:
    数据类型说明
    undefinedundefined
    nullnull
    boolean布尔值
    string字符串
    number数字
    Bigint大整数
    Object对象
    SymbolSymbol

    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传入的参数只是一个描述,实际上Symbol和Symbol并不相等。
    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...in、Object.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]

    202302220827021.png

    详解JavaScript中原始数据类型Symbol的使用4555 作者:Editor 帖子ID:2780 论坛知鸟论坛_zn60.com


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

    202302220827022.png

    详解JavaScript中原始数据类型Symbol的使用1090 作者:Editor 帖子ID:2780 论坛知鸟论坛_zn60.com


    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

    202302220827023.png

    详解JavaScript中原始数据类型Symbol的使用4624 作者:Editor 帖子ID:2780 论坛知鸟论坛_zn60.com


    b和c调用的是数组方法,那么应该是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

    202302220827024.png

    详解JavaScript中原始数据类型Symbol的使用5165 作者:Editor 帖子ID:2780 论坛知鸟论坛_zn60.com


    Symbol.species可以在创建衍生对象时使用这个属性返回的函数作为构造函数。
    这里return了Array,所以创建的衍生对象使用的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
    到此这篇关于详解JavaScript中原始数据类型Symbol的使用的文章就介绍到这了,更多相关JavaScript原始数据类型Symbol内容请搜索知鸟论坛以前的文章或继续浏览下面的相关文章希望大家以后多多支持知鸟论坛!
  • 发表于 2023-6-29 01:31:45 | 显示全部楼层
    尘埃416 2023-6-29 01:31:45 看全部
    楼主,大恩不言谢了!知鸟论坛是最棒的!
    发表于 2023-6-29 14:42:07 | 显示全部楼层
    ffycxyw2274436 2023-6-29 14:42:07 看全部
    这个帖子不回对不起自己!我想我是一天也不能离开知鸟论坛
    发表于 2023-6-29 17:37:40 | 显示全部楼层
    井底燕雀傥 2023-6-29 17:37:40 看全部
    楼主太厉害了!楼主,I*老*虎*U!我觉得知鸟论坛真是个好地方!
    发表于 2023-6-29 18:48:39 | 显示全部楼层
    知足常乐77 2023-6-29 18:48:39 看全部
    楼主,我太崇拜你了!我想我是一天也不能离开知鸟论坛
    发表于 2023-6-29 20:29:06 | 显示全部楼层
    音乐之家1 2023-6-29 20:29:06 看全部
    楼主发贴辛苦了,谢谢楼主分享!我觉得知鸟论坛是注册对了!
    发表于 2023-6-29 22:07:27 | 显示全部楼层
    123456868 2023-6-29 22:07:27 看全部
    楼主太厉害了!楼主,I*老*虎*U!我觉得知鸟论坛真是个好地方!
    发表于 2023-6-30 20:02:36 | 显示全部楼层
    啤酒瓶空了缓 2023-6-30 20:02:36 看全部
    既然你诚信诚意的推荐了,那我就勉为其难的看看吧!知鸟论坛不走平凡路。
    发表于 2023-6-30 22:39:05 | 显示全部楼层
    李志敏 2023-6-30 22:39:05 看全部
    论坛不能没有像楼主这样的人才啊!我会一直支持知鸟论坛。
    发表于 2023-6-30 23:15:28 | 显示全部楼层
    哈哈SE7 2023-6-30 23:15:28 看全部
    楼主,大恩不言谢了!知鸟论坛是最棒的!
    • 您可能感兴趣
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则 返回列表

    RSS订阅| 小黑屋| 知鸟论坛 |网站地图
    本站资源来自互联网用户收集发布,如有侵权请邮件联系处理。 联系邮箱E-mail:zniao@foxmail.com
    快速回复 返回顶部 返回列表