一文速通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)]
相关推荐
saadiya~8 分钟前
Vue 3 实现后端 Excel 文件流导出功能(Blob 下载详解)
前端·vue.js·excel
摇摇奶昔x1 小时前
webpack 学习
前端·学习·webpack
阿珊和她的猫1 小时前
Vue Router中的路由嵌套:主子路由
前端·javascript·vue.js
_龙小鱼_1 小时前
Kotlin 作用域函数(let、run、with、apply、also)对比
java·前端·kotlin
霸王蟹2 小时前
React 19中如何向Vue那样自定义状态和方法暴露给父组件。
前端·javascript·学习·react.js·typescript
小野猫子2 小时前
Web GIS可视化地图框架Leaflet、OpenLayers、Mapbox、Cesium、ArcGis for JavaScript
前端·webgl·可视化3d地图
shenyan~2 小时前
关于 js:9. Node.js 后端相关
前端·javascript·node.js
uwvwko2 小时前
ctfshow——web入门254~258
android·前端·web·ctf·反序列化
所待.3832 小时前
深入解析SpringMVC:从入门到精通
前端·spring·mvc