那些小而美的JS基础知识 - Symbol

最近在恶补JS基础,正好看到了Symbol这块,所以决定记录一下。

阅读了阮一峰老师的es6教程,现总结如下:

一、它是用来干什么的?

我们都知道对象的属性名都是字符串,这就很容易造成属性名字的冲突,导致原有的固有方法被重写(这也叫做mixin混入模式)。

这个时候就需要一种机制,来保证每个属性名字都是独一无二的。Symbol就是这种机制。

二、用法

javascript 复制代码
let a = symbol(); 
let b = symbol("foo"); 
let c = symbol("bar");

我们可以看到,symbol函数里面,参数是可有可无的。参数的作用仅仅是对当前symbol值的描述。

三、特点

  • symbol可以转化为字符串、布尔值;转化为其他类型均报错。
  • symbol不能参与计算。
  • 因为symbol值是独一无二的,所以,即使描述符相同的2个symbol值是不相等的。
  • symbol值作为属性名字时,不能使用点运算符来得到该属性,而是使用方括号的形式来get or set。因为点运算符后面总是跟着字符串。
  • symbol类型的对象属性名字,不能被 Object.keys、Object.getOwnPropertyNames、for...in...、for...of... 遍历到。

代码实践

javascript 复制代码
let b1 = 'b1';

let obj1 = {
    a: 11,
    b: 22,
    [Symbol('sty')]: 55,
    [b1]: 66
}

obj1.__proto__ = {
    c: 33
}

Object.keys(obj1);                  // 【"a","b","b1"】

Object.getOwnPropertyNames(obj1);   // 【"a","b","c1"】

Object.getOwnPropertySymbols(obj1); // 【Symbol(sty)】

四、内置的symbol类型的属性名

  • Symbol.hasInstance。
  • Symbol.isConcatSpreadable。
  • Symbol.iterator。
  • Symbol.toPrimitive。
  • Symbol.toStringTag。

4.1、Symbol.hasInstance

指向了 instanceOf 的秘密。当我们使用 instanceOf 来检测某某实例时,实际上就是调用的这个方法。

javascript 复制代码
foo instanceOf Foo;   // 等价于下面的写法

Foo[Symbol.hasInstance](foo);

4.2、Symbol.isConcatSpreadable

表示该对象是否可被array.concat方法展开。当此属性值为true时,表示此对象可以被展开。

javascript 复制代码
let arr1 = [1, 2];
arr1[Symbol.isConcatSpreadable] = false;
[].concat(arr1);   // 返回:【 【1, 2】 】

let arr2 = { length: 3, 0: 'a', 1: 'b', 2: 'c' };
arr2[Symbol.isConcatSpreadable] = true;
[].concat(arr2);   // 返回: [ 'a', 'b', 'c' ]

4.3、Symbol.iterator

当一个数据结构拥有了Symbol.iterator属性,那么它就可以与for ... of ... 一起使用。反之亦然。

4.4、Symbol.toPrimitive

这个方法是干啥的呢?

在这个内置的Symbol属性(Symbol.toPrimitive)的作用下,对象可以转换为一个原始值。

当发生强制类型转换的时候,会自动调用这个方法,这个方法接受一个字符串参数,并且值只能是"string"、"number"、"default"。

javascript 复制代码
let obj = { 
    a: 22,
    [Symbol.toPrimitive](hint){
        switch(hint){
           case 'number':
                return 100;
           case 'string':
                return '200';
           case 'default':
                return 'default';
           default:
                throw new Error('something is wrong');
        }
    }
};

obj1 == 'default';      // true

(2 * obj1) === 200;     // true

4.5、Symbol.toStringTag

我们知道,JS中提供了多种数据类型检测的方法,其中Object.prototype.toString.call这个方法屡试不爽。

原因很简单,相对来说,它是万能油。

typeof 不能检测数组跟null类型;Array.isArray只能用来检测数组;instanceOf只能用来检测引用数据类型。

那么Object.prototype.toString.call方法是如何实现的呢?

答案就是这个内置的Symbol属性。

javascript 复制代码
let obj = {
    [Symbol.toStringTag]: "这是一个陌生的属性"
}

Object.prototype.toString.call(obj);     // 返回"这是一个陌生的属性"
相关推荐
এ慕ོ冬℘゜1 小时前
前端实战:jQuery实现动态表格渲染与状态切换功能
前端·javascript·jquery
zzzzzz3101 小时前
react-bits:把酷炫动效从“灵感截图”变成可复用的 React 组件
javascript·react.js·动效
怕浪猫7 小时前
第 1 章 FDE的崛起
面试
海兰9 小时前
【应用】基于 Next.js 16 + Python mplfinance的金融K线图与技术指标可视化平台(三)
javascript·python·金融
小磊哥er10 小时前
深入解构Claude Code - 第 7 篇 · 连接外面的世界
javascript·ai编程
小磊哥er11 小时前
深入解构Claude Code - 第 6 篇 · 终端里的图形界面
javascript·ai编程
海兰11 小时前
【应用】基于 Next.js 16 + Python mplfinance的金融K线图与技术指标可视化平台(一)
javascript·python·金融
可乐鸡翅yeah_12 小时前
hls.js 内存泄漏实战排查,直播 M3U8 长时间播放异常定位方案
开发语言·javascript·python·django·ecmascript·m3u8·m3u8在线
可乐鸡翅yeah_12 小时前
第三方接口对接 M3U8 流媒体排坑实战,解决外部服务商流兼容难题
前端·javascript·python·django·html·m3u8·m3u8在线
默_笙13 小时前
🏠 「LLM Notes」:我用 Next.js + Redis 给自己造了个笔记博客
前端·javascript