Symbol 扫盲

简介: 大部分人可能都知道 symbol 是ES6 新加入的一种基本数据类型,通过 Symbol() 创建,每个 symbol 的值都不相等。

Symbol的特性


大部分人可能都知道 symbol 是ES6 新加入的一种基本数据类型,通过 Symbol() 创建,每个 symbol 的值都不相等。

const symbol = Symbol('foo');
console.log(symbol); // Symbol(foo) 其实调用了 toString()
console.log(typeof symbol); // symbol
console.log(Symbol('foo') === Symbol('foo')); // false
复制代码

上面这几行代码验证了前面的特性。

但是 Symbol 的其他特性可能还有一部分人不清楚。

Symbol 不能使用 new 操作符实例化, 因为 new 操作符返回的是一个 Symbol 包装的对象,但是 symbol 是一个基本数据类型,所以在语法层面会组织 new 操作符的实例化,抛出TypeError异常。

如果想要得到一个 Symbol 包装器对象,可以通过 Object 包装器来操作 symbol,例如

const symbolObj = new Symbol('foo') // ❌ TypeError
console.log(Object(Symbol('foo'))); // ✅ right
复制代码

1682564779(1).png

全局共享 Symbol,使用 Symbol 创建的 symbol 数据都是独一无二的,通常是用于声明一个独一无二的 key,但是某些情况下我们需要获取 symbol 的时候却不太容易,例如有两个文件,其中一个文件定义了一个对象,其中使用 symbol 声明了一个属性

export const symbol = Symbol('foo');
export const obj = {
  [symbol]: 1,
};
复制代码

我们要分别导出对象和 symbol key,我们分别导入这两个变量来看下

import { obj, symbol } from './test.js';
console.log(obj); // { [Symbol(foo)]: 1 }
console.log(obj[symbol]); // 1
console.log(obj[Symbol('foo')]); // undefined
复制代码

我们无法通过 Symbol(‘foo’)作为索引来获取到原来的值,因为使用 Symbol 创建的 symbol 都是独一无二的。这样我们只能导出 symbol,来作为索引使用,如果变量多了会非常繁杂。

这时我们可以使用 Symbol.for 方法来创建全局共享 Symbol。例如,我们将原有的 symbol 通过 Symbol.for的方式创建

const symbol = Symbol.for('foo');
export const obj = {
  [symbol]: 1,
};
复制代码

我们现在可以只导出 obj 对象,就可以获取到原本定义的 symbol 属性值,不用再将symbol 全部导出了。因为 Symbol.for 的 description 相同就会被判定为相同

import { obj } from './test.js';
console.log(obj[Symbol.for('foo')]); // 1
console.log(Symbol.for('foo') === Symbol.for('foo')) // true
复制代码

Symbol.for() 方法创建的的 symbol 会被放入一个全局 symbol 注册表中。Symbol.for() 并不是每次都会创建一个新的 symbol,它会首先检查给定的 key 是否已经在注册表中了。假如是,则会直接返回上次存储的那个。否则,它会再新建一个。

与之对应的 Symbol.keyFor()可以通过 symbol 来查找 symbol注册表中的 key 值,如果 symbol 不是通过 Symbol.for 创建的则会返回 undefined

const symbol = Symbol.for('foo');
console.log(Symbol.keyFor(symbol)); // foo
复制代码

值得一提得是用 symbol 注册的对象属性值在遍历时是不可枚举的(JSON.stringify() 也会忽略 symbol),为此我们可以使用专门的 API 来获取

const obj = {
  a: 1,
  [Symbol('foo')]: 2
}
console.log(obj); // { a: 1, [Symbol(foo)]: 2 }
console.log(Object.keys(obj)); // [ 'a' ]
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(foo) ]
复制代码


提前出现的 Symbol


虽然 symbol 在 ES6 才正式加入JS 语法,但是在 ES6 之前 Symbol 的一些方法就被用在了 JS的其他 API 中

  • Symbol.iterator:迭代器,提供迭代器的对象,可以被for … of 迭代;
  • Symbol.match:用于标识对象是否具有正则表达式的行为,例如String.prototype的 startsWith、endsWidth和includes会检查第一参数是否为正则表达式,如果是会抛出异常,此时可以通过 Symbol.match 来关闭其正则行为
const reg = /foo/
// console.log('foo'.startsWith(reg)); TypeError: First argument to String.prototype.startsWith must not be a regular expression
reg[Symbol.match] = false
console.log('/foo/'.startsWith(reg));
复制代码
  • Symbol.replace:用于指定字符串替换时调用的方法,例如
class S {
  constructor(v) {
    this.value = v
  }
  [Symbol.replace](str) {
    return `${str}/${this.value}/replace`
  }
}
const s = new S(1)
console.log('foo'.replace(s)); // foo/1/replace
复制代码
  • Symbol.search:指定了一个搜索方法,返回一个下表。
class S {
  [Symbol.search](str) {
    return 1
  }
}
const s = new S()
console.log('foo'.search(s)); // 1
复制代码
  • Symbol.split:指定一个分割方法,返回处理后的结果,String.prototype.split会调用它
  • ……其他不常用的属性
相关文章
|
网络协议 网络虚拟化 数据中心
【HCIE】13.VXLAN EVPN(一)
【HCIE】13.VXLAN EVPN
582 0
|
Prometheus Kubernetes 监控
Kubernetes 的 NameSpace 无法删除应该怎么办?
Kubernetes 的 NameSpace 无法删除应该怎么办?
|
Unix 编译器 Shell
[oeasy]python0033_先有操作系统还是先有编程语言_c语言是怎么来的
本文回顾了计算机语言与操作系统的起源,探讨了早期 Unix 操作系统及其与 C 语言的相互促进发展。Unix 最初用汇编语言编写,运行在 PDP-7 上,后来 Thompson 和 Ritchie 开发了 C 语言及编译器,使 Unix 重写并成功编译。1974 年 Ritchie 发表论文,Unix 开始被学术界关注,并逐渐普及。伯克利分校也在此过程中发挥了重要作用,推动了 Unix 和 C 语言的广泛传播。
258 10
[oeasy]python0033_先有操作系统还是先有编程语言_c语言是怎么来的
|
API 开发者
WebSocket API 中的 onerror 事件和 close 事件有什么不同?
【10月更文挑战第26天】`onerror`事件侧重于通知开发者WebSocket连接过程中出现的错误,以便进行相应的错误处理和恢复;而`close`事件则主要用于在连接关闭时进行资源清理和根据关闭情况采取适当的后续操作。两者在WebSocket应用的开发中都起着重要的作用,帮助开发者更好地管理和处理WebSocket连接的各种情况。
|
11月前
|
Python
用Pygame Zero 画矩形 (空心、实心、多个矩形、多层同心矩形、彩虹条矩形、条纹相间、随机颜色矩形、特殊效果、渐变效果)
用Pygame Zero 画矩形 (空心、实心、多个矩形、多层同心矩形、彩虹条矩形、条纹相间、随机颜色矩形、特殊效果、渐变效果)
324 40
|
运维
【10月更文挑战赛】获奖名单出炉,快来看看谁是十月创作明星!
【10月更文挑战赛】获奖名单出炉,快来看看谁是十月创作明星!
364 9
|
存储 监控 数据可视化
双十一线上服务调用链路追踪SkyWalking实战分析
【11月更文挑战第27天】随着电商行业的飞速发展,双十一购物节已成为全球最大的购物狂欢节之一。在双十一期间,电商平台需要处理海量的用户请求和订单,这对系统的稳定性和性能提出了极高的要求。为了确保系统在高并发环境下的稳定运行,对线上服务的调用链路进行追踪和分析显得尤为重要。本文将通过实战案例,详细介绍如何在双十一期间使用SkyWalking对线上服务进行调用链路追踪,并结合Seata实现分布式事务管理,从而保障系统的稳定性和性能。
377 6
|
Nacos 微服务
【微服务系列笔记】Eureka
该文档介绍了微服务注册中心的重要性和流行选项,如Eureka、Nacos、Consul和Zookeeper,强调Eureka是唯一支持跨区域调用的AP系统。接着,它提供了一个Eureka入门案例,包括设置Eureka服务器和客户端的步骤,并展示了多实例部署的效果。最后,简要总结了学习Eureka的意义,并提出了几个思考问题,如Eureka的功能、工作原理以及其他服务发现技术。
319 5
|
JSON 前端开发 JavaScript
探索JavaScript中的Async/Await:简化异步编程的利器
【10月更文挑战第12天】探索JavaScript中的Async/Await:简化异步编程的利器
266 0
|
机器学习/深度学习 数据采集 人工智能
【紧跟AI浪潮】深度剖析:如何在大模型时代精准捕获用户心声——提高召回率的实战秘籍
【10月更文挑战第5天】在深度学习领域,大型模型常面临召回率不足的问题,尤其在信息检索和推荐系统中尤为关键。本文通过具体代码示例,介绍如何提升大模型召回率。首先,利用Pandas进行数据预处理,如清洗和特征工程;其次,选择合适的模型架构,如使用PyTorch构建推荐系统;再者,优化训练策略,采用合适的损失函数及正则化技术;此外,选择恰当的评估指标,如召回率和F1分数;最后,通过后处理优化结果展示。以上方法不仅提升召回率,还增强了模型整体性能。
698 0

热门文章

最新文章