一文速通es6新特性symbol

Symbol 是 JavaScript 中的一种基本数据类型,它在 ES6(ECMAScript 2015)中被引入。Symbol 类型的值是唯一的且不可改变的,这使得它们非常适合用作对象属性的键,以避免键名冲突或用于创建私有属性。

创建 Symbol

你可以通过调用 Symbol() 函数来创建一个新的 Symbol 值。每次调用 Symbol() 都会生成一个全新的、独一无二的 Symbol。

javascript 复制代码
let sym1 = Symbol();
let sym2 = Symbol("description"); // 可选的描述字符串
  • 注意 :即使两个 Symbol 使用相同的描述字符串创建,它们仍然是不同的 Symbol。

Symbol 的特性

唯一性

每个 Symbol 都是唯一的,即使它们有相同的描述:

javascript 复制代码
let sym3 = Symbol("foo");
let sym4 = Symbol("foo");
console.log(sym3 === sym4); // false

虽然 Symbol 的描述不会影响其唯一性,但它可以在调试时提供信息。例如,当使用 console.log 输出 Symbol 或者在错误消息中显示 Symbol 时,描述可以帮助理解 Symbol 的用途。

javascript 复制代码
console.log(Symbol("foo")); // Symbol(foo)

作为对象属性键

Symbol 最常见的用途之一是作为对象属性的键。由于 Symbol 的唯一性,可以确保不会与其他属性发生命名冲突,即使这些属性来自第三方代码库。由于每一个 Symbol 值都是不相等的,这意味着只要 Symbol 值作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。

javascript 复制代码
let obj = {};
let sym = Symbol("key");

obj[sym] = "value";
console.log(obj[sym]); // value
console.log(Object.keys(obj)); // []
console.log(Object.getOwnPropertyNames(obj)); // []
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(key)]
js 复制代码
let mySymbol = Symbol();

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

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

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

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

全局符号注册表

有时你可能希望多个 Symbol 在整个应用中是共享的和可识别的。为此,JavaScript 提供了全局符号注册表,可以通过 Symbol.for 和 Symbol.keyFor 来访问。

  • Symbol.for(key):查找已存在的 Symbol 或创建一个新的 Symbol 并将其存储在全球符号注册表中。
  • Symbol.keyFor(sym):返回给定 Symbol 的键名(如果它是在全局符号注册表中定义的)。
javascript 复制代码
let symA = Symbol.for("com.example.id");
let symB = Symbol.for("com.example.id");
console.log(symA === symB); // true

console.log(Symbol.keyFor(symA)); // com.example.id

内置符号

JavaScript 还为一些内置行为定义了特殊的 Symbol,称为"well-known symbols"。这些符号通常用于指定对象的行为,并允许开发者自定义这些行为。例如:

  • Symbol.iterator:用于定义对象的默认迭代行为。
  • Symbol.toPrimitive:用于定义对象到原始值的转换。
  • Symbol.species:用于指定构造函数应返回的构造函数。
  • Symbol.hasInstance:用于自定义 instanceof 操作符的行为。
  • 等等。

Symbol 的不可枚举性

当 Symbol 用作对象属性键时,默认情况下它是不可枚举的,这意味着它不会出现在 for...in 循环中,也不会出现在 Object.keys(), Object.getOwnPropertyNames() 等方法的结果中。但是,你可以使用 Object.getOwnPropertySymbols() 来获取对象的所有 Symbol 属性。

Symbol()函数创建 Symbol 值时,可以用参数添加一个描述。

ini 复制代码
const sym = Symbol('foo');

上面代码中,sym这个值的描述就是字符串foo。

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

scss 复制代码
const sym = Symbol('foo');

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

属性名的遍历

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

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

ini 复制代码
const obj = {};
let a = Symbol('a');
let b = Symbol('b');

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

const objectSymbols = Object.getOwnPropertySymbols(obj);

objectSymbols
// [Symbol(a), Symbol(b)]
ini 复制代码
const obj = {};
const foo = Symbol('foo');

obj[foo] = 'bar';

for (let i in obj) {
  console.log(i); // 无输出
}

Object.getOwnPropertyNames(obj) // []
Object.getOwnPropertySymbols(obj) // [Symbol(foo)]
相关推荐
treasure1401 小时前
【复古】浅尝Django前后端不分离
前端·css·python·django·bootstrap·html·web
jay神3 小时前
基于 YOLOv8 的手势识别系统(Web 版)
前端·人工智能·python·深度学习·yolo·计算机视觉·计算机毕业设计
屏什么录3 小时前
长时间录屏中途崩溃:MP4 打不开的 6 种救回方案与参数设置
前端·音视频开发
code_Bo3 小时前
不只命令行:我把跨 Agent 会话同步做成了桌面应用
前端·javascript·后端
kyriewen3 小时前
AI 能把页面写出来,为什么改个需求就开始崩?
前端·javascript·人工智能
OpsEye3 小时前
同一套用例跑两个大模型接口,差异到底出在哪
javascript·ai编程
X1A0RAN4 小时前
PPT 图片批量处理教程:导出全部幻灯片 · 提取全部素材
开发语言·javascript·powerpoint
涛涛ing4 小时前
2026年最值得关注的前端变化,藏在“默认值”里
前端
量化分析码农5 小时前
股票历史数据的复权参数对照:多级别返回的字段与数值差异
java·javascript·后端
亿元程序员6 小时前
太牛了!这AI做出来的游戏,居然还能变现!
前端