一文速通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.forSymbol.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...infor...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)]
相关推荐
热爱编程的小曾10 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin22 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox34 分钟前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
-代号952739 分钟前
【JavaScript】十四、轮播图
javascript·css·css3
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX187302 小时前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞2 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox