【Javascript 漫游】【050】数据类型 Symbol

news2024/11/27 4:01:24

傍晚的车流

文章简介

本篇文章为【JavaScript 漫游】专栏的第 050 篇文章,对 ES6 规范新增的 Symbol 数据类型的知识点进行了记录。

概述

ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,我们使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入 Symbol 的原因。

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefinednull、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。

Symbol 值通过 Symbol 函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

let s = Symbol();

typeof s;
// "symbol"

注意,Symbol 函数前不能使用 new 命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。

Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。

let s1 = Symbol('foo');
let s2 = Symbol('bar');

s1; // Symbol(foo)
s2: // Symbol(bar)

s1.toString(); // "Symbol(foo)"
s2.toString(); // "Symbol(bar)"

如果 Symbol 的参数是一个对象,就会调用该对象的 toString 方法,将其转为字符串,然后才生成一个 Symbol 值。

const obj = {
  toString() {
    return 'abc';
  }
};
const sym = Symbol(obj);
sym; // Symbol(abc)

注意,Symbol 函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的 Symbol 函数的返回值是不相等的。

// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();

s1 === s2; // false

// 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');

s1 === s2; // false

Symbol 值不能与其他类型的值进行运算,会报错。

let sym = Symbol('My symbol');

"your symbol is " + sym;
// TypeError: can't convert symbol to string
`your symbol is ${sym}`
// TypeError: can't convert symbol to string

但是,Symbol 值可以显式转为字符串。

let sym = Symbol('My symbol');

String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'

另外,Symbol 值也可以转为布尔值,但是不能转为数值。

let sym = Symbol();
Boolean(sym) // true
!sym  // false

if (sym) {
  // ...
}

Number(sym) // TypeError
sym + 2 // TypeError

Symbol.prototype.description

创建 Symbol 的时候,可以添加一个描述。

const sym = Symbol('foo');

但是,读取这个描述需要将 Symbol 显式转为字符串,即下面的写法。

const sym = Symbol('foo');

String(sym); // "Symbol(foo)"
sym.toString(); // "Symbol(foo)"

上面的用法不是很方便。ES2019 提供了一个实例属性 description,直接返回 Symbol 的描述。

const sym = Symbol('foo');

sym.description; // "foo"

作为属性名的 Symbol

由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。

let mySymbol = Symbol();

// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';

// 第二种写法
let a = {
  [mySymbol]: 'Hello!';
};

// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });

// 以上写法都得到同样结果
a[mySymbol]; // "Hello!"

注意,Symbol 值作为对象属性名时,不能用点运算符。

const mySymbol = Symbol();
const a = {};
a.mySymbol = 'Hello!';
a[mySymbol]; // undefined
a['mySymbol']; // "Hello!"

同理,在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。

let s = Symbol();

let obj = {
  [s]: function (arg) { ... }
};

obj[s](123);

采用增强的对象写法,上面代码的 obj 对象可以写得更简洁一些。

let obj = {
  [s](arg) { ... }
};

Symbol 类型还可以用于定义一组常量,保证这组常量的值都是不相等。

const log = {};

log.levels = {
  DEBUG: Symbol('debug'),
  INFO: Symbol('info'),
  WARN: Symbol('warn')
};
console.log(log.levels.DEBUG, 'debug message');
console.log(log.levels.INFO, 'info message');

还有一点需要注意,Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。

属性名的遍历

Symbol 作为属性名,遍历对象的时候,该属性不会出现在 for...infor...of 循环中,也不会被 Object.keys()Object.getOwnPropertyNames()JSON.stringify() 返回。

但是,它也不是私有属性,有一个 Object.getOwnPropertySymbols() 方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

const obj = {};
let a = Symbol('a');
let b = Symbol('b');

obj[a] = 'Hello';
obj[b] = 'World';

const objectSymbols = Object.getOwnPropertySymbols(obj);

objectSymbols;
// [Symbols(a), Symbol(b)]

另一个新的 API,Reflect.ownKeys() 可以返回所有类型的键名,包括常规键名和 Symbol 键名。

let obj = {
  [Symbol('my_key')]: 1,
  enum: 2,
  nonEnum: 3
};

Reflect.ownKeys(obj);
// ["enum", "nonEnum", Symbol(my_key)]

Symbol.for()、Symbol.keyFor()

有时,我们希望重新使用同一个 Symbol 值,Symbol.for() 方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');

s1 === s2 // true

Symbol.for()Symbol() 这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for() 不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的 key 是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for(“cat”)30 次,每次都会返回同一个 Symbol 值,但是调用Symbol(“cat”)` 30 次,会返回 30 个不同的 Symbol 值。

Symbol.for("bar") === Symbol.for("bar")
// true

Symbol("bar") === Symbol("bar")
// false

Symbol.keyFor() 方法返回一个已登记的 Symbol 类型值的 key

let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"

let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined

注意,Symbol.for() 为 Symbol 值登记的名字,是全局环境的,不管有没有在全局环境运行。这个特性,可以用在不同的 iframe 或 service worker 中取到同一个值。

iframe = document.createElement('iframe');
iframe.src = String(window.location);
document.body.appendChild(iframe);

iframe.contentWindow.Symbol.for('foo') === Symbol.for('foo')
// true

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1563015.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ts 中数据约束类型

在 swagger 等接口文档中,查看 json代码,复制 将其导入到 json.cn,便于查看 在api文件夹下,新建一个定义ts类型的文件 type.ts。 定义数据类型 ---> export interface Bbb {} 调用数据类型----> export type Xxx Bbb[]…

多导购分摊业绩比例

业务场景&#xff1a; 开单是多个销售参与开单的&#xff0c;但是每个人贡献不一致&#xff0c;所以分摊的业绩比例不一致&#xff0c;总业绩比为100%。 //点击按钮&#xff0c;弹窗 <image bindtap"handleAddsales" src"/images/add.png" style"…

mongodb sharding分片模式的集群数据库,日志治理缺失导致写入数据库报错MongoWriteConcernException的问题总结(下)

一、接着上文 上文介绍了mongodb sharding的分片集群搭建&#xff0c;本文侧重于讲述日志治理。 这里使用linux自带的日志治理工具logrotate&#xff0c;无论是哪个端口的进程&#xff0c;其日志治理方式类似。 查看/data目录下的文件大小&#xff0c; du -hs *二、Logrota…

应用方案 | 内置ALC的音频前置放大器D2538A和D3308芯片

一、应用领域 D2538A和D3308是芯谷科技推出的两款内置ALC&#xff08;音频限幅器&#xff09;的前置音频放大器芯片&#xff0c;其中D2538A为单通道&#xff0c;D3308为双通道&#xff0c;它特别适用于胎心仪、个人医疗防护、立体声收录机、盒式录音机等涉及音频放大与限幅的产…

算法——矩阵,被围绕的区域

. - 力扣&#xff08;LeetCode&#xff09; 最开始也是考虑使用dfs&#xff0c;对于矩阵中的每个点&#xff0c;如果能到达边界的O&#xff0c;则跳过继续dfs。否则如果上下左右四个方向都无法到达边界的O&#xff0c;则说明当前的无法到达&#xff0c;在一个set中记录他的行数…

聚焦后成本时代赢销之道 纷享销客2024西北客户大会西安成功举办

纷享销客2024年西北客户大会西安站成功举办&#xff01;此次大会以《后成本时代的赢销之道》为主题&#xff0c;吸引了百余位客户及合作伙伴参会。 纷享销客创始人兼CEO罗旭发表演讲&#xff0c;呼吁一起凝心聚力&#xff0c;共创未来。纷享销客产品副总裁&制造行业中心总…

扫地机器人(蓝桥杯)

文章目录 扫地机器人题目描述解题思路二分贪心 扫地机器人 题目描述 小明公司的办公区有一条长长的走廊&#xff0c;由 N 个方格区域组成&#xff0c;如下图所 示。 走廊内部署了 K 台扫地机器人&#xff0c;其中第 i 台在第 Ai 个方格区域中。已知扫地机器人每分钟可以移动…

Python 自学(九) 之异常处理,文件及目录操作

目录 1. try ... except ... else ... finally 排列 P231 2. write, read, seek, readline, readlines 基本文件操作 P245 3. os模块 基本目录操作 P249 4. os.path 模块 复杂目录操作 P250 5. os 模块 高…

YoloV8改进策略:BackBone改进|GCNet(独家原创)|附结构图

摘要 本文使用GCNet注意力改进YoloV8,在YoloV8的主干中加入GCNet实现涨点。改进方法简单易用&#xff0c;欢迎大家使用&#xff01; 论文:《GCNet: Non-local Networks Meet Squeeze-Excitation Networks and Beyond》 非局部网络&#xff08;NLNet&#xff09;通过为每个查…

郭天祥新概念51单片机(第四期读书笔记)

时钟周期、状态周期、机器周期、指令周期与晶振频率之间的关系 1、晶振频率与脉冲的关系 假设单片机的晶振频率是12MHz&#xff0c;那么它的一个脉冲为1/12微秒&#xff1b;晶振单位时间发出的脉冲则为&#xff1a; 12 ∗ 1 0 6 12*10^6 12∗106。 假设单片机的晶振频率是4MH…

通过IP定位准确地址:原理、应用与局限性

在数字化时代&#xff0c;IP地址不仅是网络设备的标识符&#xff0c;同时也承载着地理位置信息。通过IP定位技术&#xff0c;我们可以根据IP地址获取到相应的地理位置信息&#xff0c;这在网络安全、数据分析、广告推送等领域有着广泛的应用。虎观代理将深入探讨通过IP定位准确…

Oracle EBS AR接口和OM销售订单单价为空数据修复

最近,用户使用客制化Web ADI 批量导入销售订单行功能,把销售订单行的单价更新成空值,直到发运确认以后,财务与客户对帐才发现大量销售订单的单价空,同时我们检查AR接口发现销售订单的单价和金额均为空。 前提条件 采用PAC成本方式具体问题症状 销售订单行的单价为空 Path:…

Spring面试常见问题

目录 1、为什么要用Spring框架&#xff1f;2、有了spring为什么又出现了 springboot&#xff1f;3、springboot出现后为什么又出现了spring cloud&#xff1f;4、SpringBoot自动配置&#xff08;重点&#xff09;5、SpringBoot启动流程&#xff08;重点&#xff09;6、简单谈一…

Latex绘制多行多TSNE列子图

Latex绘制多行多列TSNE子图 问题描述解决办法 问题描述 写论文需要绘制TSNE可视化图像。 解决办法 代码如下 \usepackage{subfigure}\begin{figure*}\centering\small\subfigure[aaa]{\includegraphics[width0.18\textwidth]{Figure/MFPT_v5_train_tsne_user0_bs0.png}}\su…

生态系统服务功能社会价值评估:当量因子法、InVEST、SolVES模型等多技术融合的探索与实践

当量因子法是将生态系统服务功能分类, 以可量化的标准构建不同类型生态系统各种服务功能的价值当量, 结合生态系统的分布面积进行评估,该方法数据量少, 较为直观易用, 适用于区域和全球尺度生态系统服务价值的评估。基于GIS平台的InVEST模型以空间数据为基础&#xff0c;量化多…

gin源码分析(1)--初始化中间件,路由组与路由树

目标 关于gin.Default()&#xff0c;gin.New()&#xff0c;gin.Use()group与子group之间的关系&#xff0c;多group与middleware之间关系中间件的类型&#xff0c;全局&#xff0c;group&#xff0c;get&#xff0c;不同类型的中间件什么时候执行。中间件 next 和abort行为如何…

代码+视频,手动绘制logistic回归预测模型校准曲线(Calibration curve)(1)

校准曲线图表示的是预测值和实际值的差距&#xff0c;作为预测模型的重要部分&#xff0c;目前很多函数能绘制校准曲线。 一般分为两种&#xff0c;一种是通过Hosmer-Lemeshow检验&#xff0c;把P值分为10等分&#xff0c;求出每等分的预测值和实际值的差距. 另外一种是calibra…

vue 响应式原理 Object.defineProperty(obj,‘属性名A‘,options);

目录 self简单讲解1. 视图影响数据2. 数据影响视图3. 视图数据双向影响页面展示 百度 self 简单讲解 get和set方法是ES5中提供的&#xff0c;因为是方法&#xff0c;所以可以进行判断&#xff0c;get 一般是要通过 return 返回的&#xff1b;而 set 是设置&#xff0c;不用返回…

回收站删除的文件在哪里?专业恢复方法分享(最新版)

“我很想知道我从回收站删除的文件被保存在哪里了呢&#xff1f;我刚刚不小心清空了回收站&#xff0c;现在想将它们恢复&#xff0c;应该怎么操作呢&#xff1f;谁能教教我怎么从回收站恢复文件&#xff1f;” 回收站&#xff0c;作为Windows操作系统中的一个重要组件&#xf…

探索AI技术创业的三大机遇

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 方向一&#xff1a;行业解决方案 方向二&#xff1a;智能产品和服务 方向三&#xff1a;教育和培训 结语 我的其他博客 前言…