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、线程饥饿 什么是线程安全性问题? 我们可以这么理解&#…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...