JS中Symbol的介绍
1、 引入Symbol类型的背景
ES5 的对象属性名都是字符串,这容易造成属性名冲突的问题
举例: 使用别人的模块/对象, 又想为之添加新的属性,这就容易使得新属性名与原有属性名冲突
2、Symbol类型简介
symbol是一种原始数据类型
- 其余原始类型: 未定义(undefined) 、 空值(null)、布尔值(boolean)、字符串(string)、数值(number)、对象(object)
- symbol表示独一无二的值
- symbol类型的"真实值"无法获取,也就是说Symbol类型没有对应的字面量
- symbol类型的意义在于区分彼此和不重复,不在于真实值
Symbol()是一种原生函数
- 常见的原生函数有String()、Number()、Boolean()、Array()、Object()、Function()、RegExp()、Date()、Error()、Symbol()
3、基本用法
符号需要使用Symbol()函数初始化。
let sym = Symbol();
// 因为符号本身是原始类型,所以typeof操作符对符号返回symbol
console.log(typeof sym); // symbol
调用Symbol()函数时,也可以传入一个字符串参数作为对符号的描述,将来可以通过这个字符串来调试代码。但是,这个字符串参数与符号定义或标识完全无关:
// Symbol的值是唯一的,不会出现相同值的常量
let genericSymbol = Symbol();
let otherGenericSymbol = Symbol();
console.log(genericSymbol == otherGenericSymbol); // false// 可以传入一个字符串参数作为对符号的描述
let fooSymbol = Symbol('foo');
let otherFooSymbol = Symbol('foo');
console.log(fooSymbol == otherFooSymbol); // false
符号没有字面量语法。 按照规范,只要创建Symbol()实例并将其用作对象的新属性,就可以保证它不会覆盖已有的对象属性,无论是符号属性还是字符串属性。
let genericSymbol = Symbol();
console.log(genericSymbol); // Symbol()let fooSymbol = Symbol('foo');
console.log(fooSymbol); // Symbol(foo)
Symbol()函数不能与new关键字一起作为构造函数使用。
这样做是为了避免创建符号包装对象,像使用Boolean、String或Number那样,它们都支持构造函数且可用于初始化包含原始值的包装对象。
let myBoolean = new Boolean();
console.log(typeof myBoolean); // "object"let myString = new String();
console.log(typeof myString); // "object"let myNumber = new Number();
console.log(typeof myNumber); // "object"let mySymbol = new Symbol(); // 报错,TypeError
console.log(mySymbol);
如果想使用符号包装对象,可以借用Object()函数:
let mySymbol = Symbol();
let myWarppedSymbol = Object(mySymbol);
console.log(typeof myWarppedSymbol); // "object"
4、 使用全局符号注册表
如果运行时的不同部分需要共享和重用符号实例,那么可以用一个字符串作为键,在全局符号注册表中创建并重用符号。
Symbol.for()方法:
let fooGlobalSymbol = Symbol.for('foo');
console.log(typeof fooGlobalSymbol); // symbol
Symbol.for()对每个字符串键都执行幂等操作。
第一次使用某个字符串调用时,它会检查全局运行时注册表,发现不存在对应的符号,于是就会生成一个新符号实例并添加到注册表中。
后续使用相同字符串的调用同样会检查注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例。
// 创建新符号
let fooGlobalSymbol = Symbol.for('foo');
// 重用已有符号
let otherFooGlobalSymbol = Symbol.for('foo');console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
采用相同符号,在全局注册表中定义的符号跟使用Symbol()定义的符号也不等同:
// 使用Symbol()定义
let localSymbol = Symbol('foo');
// 使用全局注册表定义
let globalSymbol = Symbol.for('foo');console.log(localSymbol === globalSymbol); // false
全局注册表中的符号必须使用字符串键来创建,因此作为参数传给Symbol.for()的任何值都会被转换为字符串。
注册表中使用的键同时也会被用作符号描述。
let emptyGlobalSymbol = Symbol.for();
console.log(emptyGlobalSymbol); // Symbol(undefined)
使用Symbol.keyFor()来查询全局注册表,这个方法接收符号,返回该全局符号对应的字符串键。如果查询的不是全局符号,则返回undefined。
// 创建全局符号
let s = Symbol.for('foo');
console.log(Symbol.keyFor(s)); // foo// 创建普通符号
let s2 = Symbol('bar');
console.log(Symbol.keyFor(s2)); // undefined
如果传给Symbol.keyFor()的不是符号,则该方法抛出TypeError。
Symbol.keyFor(123); // TypeError: 123 is not a symbol
5、 使用符号作为属性
凡是可以使用字符串或数值作为属性的地方,都可以使用符号。
包括对象字面量属性和 Object.defineProperty(obj, prop, descriptor) / Object.defineProperties() 定义的属性。
对象字面量只能在计算属性语法中使用符号作为属性。
let s1 = Symbol('foo'),s2 = Symbol('bar'),s3 = Symbol('baz'),s4 = Symbol('qux');let o = {// [属性],会对属性进行读取,并且转换成字符串。[s1]是读取了Symbol的字符串键'foo'[s1]: 'foo val'
};
// 或 o[s1] = 'foo val';
console.log(o); // { [Symbol(foo)]: 'foo val' }Object.defineProperty(o, s2, { value: 'bar val' });
console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val}Object.defineProperties(o, {[s3]: { value: 'baz val' },[s4]: { value: 'qux val' }
});
console.log(o); // {Symbol(foo): foo val, Symbol(bar): baz val,// Symbol(foo): foo val, Symbol(bar): qux val}
let s1 = Symbol('foo'),s2 = Symbol('bar');let o = {[s1]: 'foo val',[s2]: 'bar val',baz: 'baz val',qux: 'qux val'
};// Object.getOwnPropertySymbols()返回对象实例的符号属性数组
console.log(Object.getOwnPropertySymbols(o)); // [ Symbol(foo), Symbol(bar) ]// Object.getOwnPropertyNames()返回对象实例的常规属性数组
console.log(Object.getOwnPropertyNames(o)); // [ 'baz', 'qux' ]// Object.getOwnPropertyDescriptors()会返回同时包含常规和符号属性描述符的对象
console.log(Object.getOwnPropertyDescriptors(o));
// {
// baz: {
// value: 'baz val',
// writable: true,
// enumerable: true,
// configurable: true
// },
// qux: {
// value: 'qux val',
// writable: true,
// enumerable: true,
// configurable: true
// },
// [Symbol(foo)]: {
// value: 'foo val',
// writable: true,
// enumerable: true,
// configurable: true
// },
// [Symbol(bar)]: {
// value: 'bar val',
// writable: true,
// enumerable: true,
// configurable: true
// }
// }// Reflect.ownKeys()会返回两种类型的键
console.log(Reflect.ownKeys(o)); // [ 'baz', 'qux', Symbol(foo), Symbol(bar) ]
注意:Object.getOwnPropertyNames()和Object.getOwnProperty-Symbols()两个方法的返回值彼此互斥。
因为符号属性是对内存中符号的一个引用,所以直接创建并用作属性的符号不会丢失。
但是,如果没有显式地保存对这些属性的引用,那么必须遍历对象的所有符号属性才能找到相应的属性键。
let o = {[Symbol('foo')]: 'foo val',[Symbol('bar')]: 'bar val'
};
console.log(o); // { [Symbol(foo)]: 'foo val', [Symbol(bar)]: 'bar val' }let barSymbol = Object.getOwnPropertySymbols(o).find((Symbol) => Symbol.toString().match(/bar/));
console.log(barSymbol); // Symbol(bar)
6、 所有属性
| 属性 | 含义 |
|---|---|
| Symbol.asyncIterator | 符号指定了一个对象的默认异步迭代器。如果一个对象设置了这个属性,它就是异步可迭代对象,可用于for await…of循环。 |
| Symbol.prototype.description | description 是一个只读属性,它会返回 Symbol 对象的可选描述的字符串。 |
| Symbol.hasInstance | 用于判断某对象是否为某构造器的实例。因此你可以用它自定义 instanceof 操作符在某个类上的行为。 |
| Symbol.isConcatSpreadable | 用于配置某对象作为Array.prototype.concat()方法的参数时是否展开其数组元素。 |
| Symbol.iterator | 为每一个对象定义了默认的迭代器。该迭代器可以被 for…of 循环使用。 |
| Symbol.match | 指定了匹配的是正则表达式而不是字符串。String.prototype.match() 方法会调用此函数 |
| Symbol.matchAll | 内置通用(well-known)符号指定方法返回一个迭代器,该迭代器根据字符串生成正则表达式的匹配项。此函数可以被 String.prototype.matchAll() 方法调用。 |
| Symbol.replace | 这个属性指定了当一个字符串替换所匹配字符串时所调用的方法。 |
| Symbol.search | 指定了一个搜索方法,这个方法接受用户输入的正则表达式,返回该正则表达式在字符串中匹配到的下标,这个方法由以下的方法来调用 String.prototype.search()。 |
| Symbol.species | 知名的 Symbol.species 是个函数值属性,其被构造函数用以创建派生对象。 |
| Symbol.split | 指向 一个正则表达式的索引处分割字符串的方法。这个方法通过 String.prototype.split() 调用。 |
| Symbol.toPrimitive | 是内置的 symbol 属性,其指定了一种接受首选类型并返回对象原始值的表示的方法。它被所有的强类型转换制算法优先调用。 |
| Symbol.toStringTag | 内置通用(well-known)symbol 是一个字符串值属性,用于创建对象的默认字符串描述。它由 Object.prototype.toString() 方法内部访问。 |
| Symbol.unscopables | 指用于指定对象值,其对象自身和继承的从关联对象的 with 环境绑定中排除的属性名称。 |
相关文章:
JS中Symbol的介绍
1、 引入Symbol类型的背景 ES5 的对象属性名都是字符串,这容易造成属性名冲突的问题 举例: 使用别人的模块/对象, 又想为之添加新的属性,这就容易使得新属性名与原有属性名冲突 2、Symbol类型简介 symbol是一种原始数据类型 其余原始类型: 未定义(undefined) 、…...
封装统一响应结果类和消息枚举类
在开发中,响应结果都需要统一格式,下面给出一个例子,可自行修改。 package com.lili.utils;import com.fasterxml.jackson.annotation.JsonInclude; import com.lili.enums.AppHttpCodeEnum;import java.io.Serializable;/*** author YLi_Ji…...
应广单片机实现红蓝双色爆闪灯
继续进行点灯,今天来点简单的,红蓝双色爆闪灯,上电即可爆闪,红色接pa.3.pa.4,蓝色接pa6.和pa.7,低电平点亮LED灯,想要高电平点亮,或是驱动N管点亮灯,可以稍作修改。端口电平输出0改1,…...
深入了解OSI模型:计算机网络的七大层次
目录 OSI模型 物理层 数据链路层 网络层 传输层 会话层 表示层 应用层 OSI模型 OSI模型是一个网络通信的概念模型,用于描述计算机网络中各个不同层次之间的通信和功能。它将网络通信分为七个不同的层次,每个层次负责不同的任务,使得网…...
games101 作业2
题目 光栅化一个三角形 1. 创建三角形的 2 维 bounding box。 2. 遍历此 bounding box 内的所有像素(使用其整数索引)。然后,使用像素中心的屏幕空间坐标来检查中心点是否在三角形内。 3. 如果在内部,则将其位置处的插值深度值 (…...
二叉树链式存储结构
目录 1.二叉树链式存储结构 2.二叉树的遍历 2.1 前、中、后序遍历 2.2 层序遍历 3.二叉树的其他递归问题 3.1 二叉树的结点个数 3.2 二叉树的叶子结点个数 3.3 二叉树第k层结点个数 3.4 二叉树的深度 3.5 二叉树查找 3.6 二叉树销毁 4.二叉树的基础OJ题 4.1 单值…...
Claude 使用指南 | 可与GPT-4媲美的语言模型
本文全程干货,让你轻松使用上claude,这也是目前体验cluade的唯一途径!废话不多说,直接上教程,cluade的能力不逊于GPT4,号称是ChatGPT4.0最强竞品。相对Chatgpt来说,Claude不仅是完全免费的&…...
【汇编】微处理器
【汇编】微处理器 文章目录 【汇编】微处理器1、微处理器概念1.1 关键词1.2 分类 2、微处理器结构2.1 寄存器2.2 寄存器&汇编助记符2.3 寄存器组成结构 3、地址空间3.1 存储空间3.1.1 虚拟空间(编程空间)3.1.2 线性空间 3.2 I/O空间 4、工作模式4.1 …...
按键点亮led灯
原理图: K0这个按键按下时,开发板D1这个灯亮,松开,灯灭 代码如下: #include "stm32f4xx.h" void LED_Init(void) {//1.定义一个GPIO外设的结构体变量 GPIO_InitTypeDef GPIO_InitStructure;//RCC_AHB1PeriphClockCmd(RCC_AHB1Pe…...
Java常见面试题
目录 1、mysql并发事务会带来哪些问题,如何解决?2、请详细描述Redis持久化机制?3、简述Redis缓存雪崩和缓存穿透的问题和解决方案?4、RabbitMQ消息丢失及对应解决方案5、什么叫线程安全?举例说明6、举例说明常用的加密…...
笔记1.5:计算机网络体系结构
从功能上描述计算机网络结构 分层结构 每层遵循某个网络协议完成本层功能 基本概念 实体:表示任何可发送或接收信息的硬件或软件进程。 协议是控制两个对等实体进行通信的规则的集合,协议是水平的。 任一层实体需要使用下层服务,遵循本层…...
【Python】Python 连接字符串应优先使用 join 而不是 +
Python 连接字符串应优先使用 join 而不是 简介 字符串处理在大多数编程程序语言中都不可避免,字符串的连接也是在编程过程中经常需要面对的问题。 Python中的字符串与其他一些程序语言如C、Java有一些不同,它为不 可变对象。 一旦创建便不能改变&…...
uniapp 小程序 父组件调用子组件方法
答案:配合小程序API > this.selectComponent(""),来选择组件,再使用$vm选择组件实例,再调用方法,或者data 1 设置组件的id,如果你的多端,请跟据情况设置ref,class,id,以便通过小…...
Vue-01:MVVM数据双向绑定与Vue的生命周期
一、Vue介绍 1.1 什么是Vue ? Vue是一个渐进式的JavaScript框架,用于构建用户界面。"渐进式"意味着Vue的设计理念是逐步增强应用的功能和复杂性,而不是一次性地引入所有功能。这使得开发者可以根据项目需求选择性地使用Vue的不同特…...
数据通信网络之OSPFv3基础
文章及资源归档至【AIShareLab】,回复 通信系统与网络 可获取。 文章目录 一、目的二、拓扑三、需求四、步骤 一、目的 掌握路由器的IPv6 基础配置。掌握OSPFv3(单区域)的基础配置。 二、拓扑 如图1 所示,三台路由器R1、R2 和R…...
FPGA-结合协议时序实现UART收发器(五):串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive
FPGA-结合协议时序实现UART收发器(五):串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive 串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive,功能实现。 文章目录 FPGA-结合协议时序实现UART收发器(五&…...
我学编程全靠B站了,真香-国外篇(第三期)
你好,我是Martin。 今天来点猛料,给大家推荐点我的压箱收藏-国外知名大学的公开课。 我推荐的不多,本着少就是多的原则,只给大家推荐我看过最好的五门视频,主要是来自两所国外高校:MIT美国麻省理工、CMU卡…...
c++ 变量常量指针练习题
Q1:在win32 x86模式下,int *p; int **pp; double *q; 请说明p、pp、q各占几个字节的内存单元。 p 占 4 个字节 pp 占 4 个字节 q 占 4 个字节 Q2常量1、1.0、“1”的数据类型是什么? 1 是 整形 int 1.0 是 浮点型 double “1” 是 const char * Q3 语句&…...
Linux底层基础知识
一.汇编,C语言,C,JAVA之间的关系 汇编,C语言,C可以通过不同的编译器,编译成机器码。而java只能由Java虚拟机识别。Java虚拟机可以看成一个操作系统,Java虚拟机是由汇编,C,…...
JUC并发编程--------线程安全篇
目录 什么是线程安全性问题? 如何实现线程安全? 1、线程封闭 2、无状态的类 3、让类不可变 4、加锁和CAS 并发环境下的线程安全问题有哪些? 1、死锁 2、活锁 3、线程饥饿 什么是线程安全性问题? 我们可以这么理解&#…...
咨询进阶——详解《商业模式思维的30个技巧》
《商业模式思维的30个技巧》读书笔记可提炼关键技巧:如用价值链连接客户价值、深入理解客户细分与价值定位、灵活调整商业模式、制定差异化定价策略、履行社会责任、持续创新及重视人才管理等[3][18]。 详答 一、核心技巧提炼 客户价值与价值链连接 构建价值传递机制:通过价…...
告别命令行恐惧:用Docker Compose 5分钟拉起一个开箱即用的Yapi服务
告别命令行恐惧:用Docker Compose 5分钟拉起一个开箱即用的Yapi服务 在API开发协作中,Yapi作为一款优秀的接口管理工具,能显著提升团队效率。但传统部署方式往往让人望而却步——需要手动安装MongoDB、配置Node.js环境、解决Python依赖&#…...
形式验证实战:5个降低状态空间复杂度的黑科技(附内存控制器案例)
形式验证实战:5个降低状态空间复杂度的黑科技(附内存控制器案例) 在芯片设计领域,形式验证(Formal Verification, FV)正逐渐成为确保设计正确性的重要手段。然而,随着设计复杂度的提升ÿ…...
**React 项目实战:从状态管理到性能优化的全流程精讲与代码实操**在现代前端开发中
React 项目实战:从状态管理到性能优化的全流程精讲与代码实操 在现代前端开发中,React 已成为构建复杂单页应用(SPA)的事实标准。但如何真正发挥其潜力?本文将带你深入理解 React 的核心机制,并通过一个完整…...
电路接口技术解析:从TTL到无线通信的演进
1. 电路接口概述:信号传输的关键桥梁在嵌入式系统和电子电路设计中,接口技术就像城市之间的高速公路系统。当不同模块需要通信时,就像不同方言的人群需要找到共同语言。我曾参与过一个工业控制器项目,CPU与传感器间的通信故障导致…...
数据治理与数据质量:从策略到实践
数据治理与数据质量:从策略到实践 前言 作为一个在数据深渊里捞了十几年 Bug 的女码农,我深知数据治理和数据质量在企业数据管理中的重要性。随着数据量的爆炸式增长和数据类型的多样化,数据治理和数据质量已经成为企业数据管理的核心挑战。今…...
如何用嘎嘎降AI处理文献综述部分:综述专项降AI教程
如何用嘎嘎降AI处理文献综述部分:综述专项降AI教程 这篇教程来自实操经验。帮三个同学处理过论文AI率,加上自己的,前后操作了十几次。把流程总结成教程,尽量详细。 核心工具推荐嘎嘎降AI(www.aigcleaner.com…...
PrimeTime实战指南:从基础STA流程到精准时序报告解析
1. PrimeTime与静态时序分析基础 刚接触PrimeTime时,我和大多数工程师一样被满屏的时序报告搞得头晕眼花。直到把整个设计流程跑通三遍后,才真正理解这个工具的价值。PrimeTime(简称PT)是Synopsys推出的静态时序分析黄金工具&…...
如何快速配置MangoHud快捷键:从零开始的游戏性能监控终极指南
如何快速配置MangoHud快捷键:从零开始的游戏性能监控终极指南 【免费下载链接】MangoHud A Vulkan and OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more. 项目地址: https://gitcode.com/gh_mirrors/ma/MangoHud 你是否厌倦了游戏性…...
ZenTimings终极指南:解锁AMD Ryzen内存性能的完整解决方案
ZenTimings终极指南:解锁AMD Ryzen内存性能的完整解决方案 【免费下载链接】ZenTimings 项目地址: https://gitcode.com/gh_mirrors/ze/ZenTimings ZenTimings是一款专为AMD Ryzen平台设计的专业内存时序监控与优化工具,能够帮助用户深入了解和调…...
