当前位置: 首页 > news >正文

es6中的symbol基础知识

ES6 中的 Symbol 是一种新的原始数据类型(Primitive Data Type),它代表唯一的、不可变的值。它的主要目的是为了解决属性名冲突的问题,并为对象定义非字符串的属性键(Key)。

以下是 Symbol 的核心特性和用法:

1. 创建 Symbol

  • 使用 Symbol() 函数创建,每次调用都会返回一个独一无二的值:
    const sym1 = Symbol();
    const sym2 = Symbol();
    console.log(sym1 === sym2); // false
    
  • 可以传入一个可选的字符串参数作为描述(Description),主要用于调试目的,不影响唯一性:
    const sym3 = Symbol('description');
    const sym4 = Symbol('description');
    console.log(sym3 === sym4); // false (即使描述相同,值也不同)
    

2. 核心特性

  • 唯一性: 每个 Symbol 值都是唯一的,无论描述是否相同。这是其最核心的特性。
  • 不可变性: Symbol 值一旦创建就不能被修改。
  • 原始类型: typeof 操作符返回 'symbol'
    console.log(typeof Symbol()); // 'symbol'
    

3. 主要用途:对象属性键

  • Symbol 的主要价值在于作为对象的属性名(Key)
  • 使用 Symbol 作为属性名可以避免命名冲突,尤其是在扩展第三方库的对象或定义对象内部的元属性时非常有用。
  • 定义 Symbol 属性:
    const mySymbol = Symbol('myKey');
    const obj = {};
    // 方法1: 直接使用方括号
    obj[mySymbol] = 'value';
    // 方法2: 在对象字面量中定义 (需要方括号)
    const obj2 = {[mySymbol]: 'value'
    };
    // 方法3: 使用 Object.defineProperty
    Object.defineProperty(obj, mySymbol, { value: 'value' });
    
  • 访问 Symbol 属性:
    console.log(obj[mySymbol]); // 'value'
    
  • 重要:Symbol 属性在常规遍历中不可见:
    • for...in 循环不会枚举 Symbol 属性。
    • Object.keys(obj) 不会返回 Symbol 属性。
    • Object.getOwnPropertyNames(obj) 不会返回 Symbol 属性。
    • 需要使用 Object.getOwnPropertySymbols(obj) 来获取对象自身的所有 Symbol 属性:
      const symbols = Object.getOwnPropertySymbols(obj);
      console.log(symbols); // [ Symbol(myKey) ]
      console.log(obj[symbols[0]]); // 'value'
      
    • Reflect.ownKeys(obj) 会返回所有类型的键(包括字符串和 Symbol):
      console.log(Reflect.ownKeys(obj)); // [ ...other keys..., Symbol(myKey) ]
      

4. 全局 Symbol 注册表

  • Symbol.for(key):在全局 Symbol 注册表中查找或创建一个与给定字符串 key 关联的 Symbol。
    • 如果存在与 key 关联的 Symbol,则返回它。
    • 如果不存在,则创建一个新的 Symbol 并与 key 关联后返回。
    • 相同 key 调用 Symbol.for() 总是返回同一个 Symbol。
    const globSym1 = Symbol.for('globalKey');
    const globSym2 = Symbol.for('globalKey');
    console.log(globSym1 === globSym2); // true
    
  • Symbol.keyFor(sym):查询全局注册表,返回给定 Symbol 关联的字符串键(如果该 Symbol 是通过 Symbol.for() 创建并注册的)。如果不是全局注册的 Symbol,则返回 undefined
    console.log(Symbol.keyFor(globSym1)); // 'globalKey'
    console.log(Symbol.keyFor(sym1)); // undefined (sym1 不是全局注册的)
    

5. 内置 Symbol 值 (Well-known Symbols)

  • ES6 定义了一系列内置的 Symbol 值,它们代表了语言内部的、对象可定制的方法或行为。这些 Symbol 存储在 Symbol 的静态属性上。
  • 常见的内置 Symbol:
    • Symbol.iterator: 定义对象的默认迭代器。被 for...of 循环使用。
    • Symbol.hasInstance: 自定义 instanceof 操作符的行为。
    • Symbol.toStringTag: 定义 Object.prototype.toString.call() 返回的字符串 [object XXXX] 中的 XXXX
    • Symbol.isConcatSpreadable: 控制数组或类数组对象在 Array.prototype.concat() 中是否被展开。
    • Symbol.species: 指定创建派生对象(如 map, filter 返回的新数组)时使用的构造函数。
    • Symbol.toPrimitive: 定义对象如何被转换为原始值(在涉及 +, ==, String(), Number() 等操作时)。
    • Symbol.match/Symbol.replace/Symbol.search/Symbol.split: 自定义对象在作为 String.prototype.match()/replace()/search()/split() 方法的第一个参数时的行为。
  • 示例 (自定义 toStringTag):
    class MyCollection {get [Symbol.toStringTag]() {return 'MyAwesomeCollection';}
    }
    const coll = new MyCollection();
    console.log(Object.prototype.toString.call(coll)); // '[object MyAwesomeCollection]'
    

6. 注意事项

  • 类型转换: Symbol 不能隐式转换为字符串或数字(尝试会抛出 TypeError)。如果需要字符串表示,必须显式调用 .toString() 或使用 .description 属性(ES2019+)。
    const sym = Symbol('desc');
    console.log(sym.toString()); // 'Symbol(desc)'
    console.log(sym.description); // 'desc' (ES2019+)
    // console.log('Symbol: ' + sym); // TypeError!
    
  • JSON 序列化: JSON.stringify() 会完全忽略对象的 Symbol 属性键和值。
  • 不是真正的私有: 虽然 Symbol 属性在常规遍历中不可见,但通过 Object.getOwnPropertySymbols()Reflect.ownKeys() 仍然可以获取到。它们提供的是非冲突的、半隐藏的属性,而非严格的私有属性(真正的私有属性需要 ES2022+ 的 # 语法)。

总结

ES6 的 Symbol 是一种用于创建唯一标识符的原始数据类型。它的核心价值在于:

  1. 创建唯一属性键: 从根本上避免对象属性名冲突,特别适合库开发、元编程和定义对象内部特殊行为。
  2. 定义内置行为: 通过内置 Symbol(如 Symbol.iterator, Symbol.toStringTag)暴露语言的内部机制,允许开发者自定义对象在特定操作(迭代、类型转换、字符串匹配等)中的行为。
  3. 全局共享符号: 通过 Symbol.for()Symbol.keyFor() 实现在不同作用域或模块间共享相同的 Symbol。

理解 Symbol 及其应用(尤其是内置 Symbol)是掌握现代 JavaScript 高级特性和元编程能力的关键一步。

http://www.dtcms.com/a/292498.html

相关文章:

  • 在Android开发中,如何获取到手机设备的PIN码?
  • 如何安装CMake较新的版本
  • Apache Ignite 长事务终止机制
  • 精密全波整流电路(一)
  • torchvision.transforms 与 MONAI 数据增强的异同
  • Cloud 与 VPS 的区别:如何选择最适合你的服务器解决方案?
  • stream流入门
  • 【打怪升级 - 01】保姆级机器视觉入门指南:硬件选型 + CUDA/cuDNN/Miniconda/PyTorch 安装全流程(附版本匹配秘籍)
  • vmware 克隆虚拟机,报错:克隆时出错:指定不存在的设备。然后电脑卡死,只能强制关机再开机。
  • FastDFS 6.11.0 单机环境搭建与测试(附 Nginx 集成)+ docker构建+k8s启动文件
  • 用org.apache.pdfbox 转换 PDF 到 图片格式
  • KafkaMQ 日志采集最佳实践
  • Python 正则表达式:入门到实战
  • 日常随笔-React摘要
  • 【ROS/DDS】FastDDS :编写FastDDS程序实现与ROS2 通讯(四)
  • 深入浅出理解 TCP 与 UDP:网络传输协议的核心差异与应用
  • 平台端用户管理功能设计全解:从分类管控到审核闭环
  • 基于springboot的疫苗发布和接种预约系统(论文+开题报告)
  • 实现分布式锁
  • 腾讯云SDK
  • 论文笔记:Parameter Competition Balancing for Model Merging
  • MongoDB频繁掉线频繁断开服务的核心原因以及解决方案-卓伊凡|贝贝|莉莉|糖果
  • 在Windows 10/11上使用Qt和SOEM构建EtherCAT主站:工业控制新纪元
  • 【Axure视频教程】形状地图
  • Qt 事件处理机制深入剖析
  • 【OpenCV篇】OpenCV——01day.图像基础
  • 通俗易懂循环神经网络(RNN)指南
  • cookie基本使用
  • 如何用keepAlive实现标签页缓存
  • Samba 共享解决方案:微服务多机共享 `/app` 目录