JavaScript Symbols 基础知识






4.94/5 (8投票s)
JavaScript Symbol 类型简介
引言
截至本文撰写之时,Symbol 是最新的 JavaScript 原始类型。事实上,许多开发者(包括我最初)都不知道这个功能的存在。为一门语言引入新功能意味着为该语言带来好处,我们应该理解某个特定功能的具体用途。因此,我们将探讨 JavaScript Symbols 的好处及其特定用途。好了,我们开始吧。
目录
什么是 JavaScript Symbol?
JavaScript Symbol 是 ES6 中引入的一种新的原始类型。此外,Symbol 是一种唯一且不可变的值。创建新的 Symbol 非常简单,只需调用 `Symbol()` 函数即可,该函数每次调用时都会返回一个唯一的 Symbol。稍后将在示例中详细介绍。
JavaScript Symbol 的好处和用法?
创建新的 JavaScript Symbol 总是唯一的
正如我们在上一节中所描述的,我们说过,为了创建一个新的 JavaScript Symbol,我们只需要调用 `Symbol` 函数。关于它的另一件事需要提到,Symbol 没有字面量形式;因此,我们只能使用 `Symbol()` 函数来创建一个。
请看下面的示例。
//how to create a Symbol
const mySymbol1 = Symbol();
const mySymbol2 = Symbol();
console.log(mySymbol1, mySymbol2);
//output: Symbol() Symbol()
带描述的 JavaScript Symbol,主要用于调试
现在,我们已经看到了如何创建一个新的 JavaScript Symbol。不要忘记,`Symbol()` 函数接受一个可选的字符串参数,该参数代表 `Symbol` 的描述。根据我的经验,描述用于调试目的,而不是用于访问 `Symbol` 本身。
请看下面的示例
//* how to create a Symbol with description
const mySymbolWithDescription1 = Symbol("First description");
const mySymbolWithDescription2 = Symbol("Second description");
console.log(mySymbolWithDescription1, mySymbolWithDescription2);
//output: Symbol(First description) Symbol(Second description)
具有相同描述的 JavaScript Symbol 不相等
Symbol 总是 100% 保证是唯一的。请记住,描述只是一个 `标签`,不会影响任何事情。再说一遍,描述只是一个 `标签`,仅此而已。
请看下面的示例
//Symbol with same description aren't equal
const mySymbol_1 = Symbol("Cat");
const mySymbol_2 = Symbol("Cat");
console.dir(mySymbol_1 === mySymbol_2);
//output: false
调用新实例时使用 Symbol() 函数
我第一次学习 JavaScript Symbol 时,以为可以使用 `Symbol()` 函数创建一个新实例。结果,它抛出了一个错误,说:`“Symbol is not a constructor”`(Symbol 不是构造函数),在创建新实例时。
请看下面的示例
//how not to create a Symbol
try {
const _newSymbols = new Symbol();
} catch (error) {
console.dir(error.message); //output: Symbol is not a constructor
}
所以,正如你在上面的例子中所看到的,使用 new 关键字来创建一个 `Symbol` 的新实例是行不通的,因为根据我们之前的章节,我们必须直接调用 `Symbol()` 函数。
JavaScript Symbol 类型及其转换为字符串
使用 `typeof` 运算符一直很有趣。因此,结果将是 `symbol` 而不是 `object`,因为它是一种原始类型。
根据我的观察,JavaScript 类型支持隐式转换为 `string`。然而,`Symbol` 类型不会自动转换。你确实需要显式调用 `.toString()` 方法。
使用 typeof 运算符检查类型
//Let's check if the type name of Symbol
const mySymbolType = Symbol();
console.log(typeof mySymbolType);
//output: symbol
在 alert 函数中调用 Symbol 类型
const mySymbolType = Symbol();
alert(mySymbolType);
//output: Uncaught TypeError: Cannot convert a Symbol value to a string
显式使用 .toString() 和 description 属性
const _newSymbols2 = Symbol("Hello");
console.log(_newSymbols2.toString()); //output: Symbol(Hello)
console.log(_newSymbols2.description); //output: Hello
将 JavaScript Symbol 用作对象键
截至今天,JavaScript 对象属性键可以是字符串或 Symbol。此外,拥有 `Symbol` 类型属性的对象在尝试枚举对象键时不会被列出。因此,在我看来,当您枚举时它看起来是隐藏的,但当您使用 `[]` 令牌时并非如此。
请看下面的示例
const customerSymbol = Symbol("Object date created");
let customer = {
name: "Jin Vincent Necesario",
[customerSymbol]: new Date()
};
console.log(customer);
输出
我们尝试使用 for-in 循环进行枚举
for (const key in customer) {
if (customer.hasOwnProperty(key)) {
console.log(`customer.${key} is equals to ${customer[key]}`);
}
}
//output: customer.name is equals to Jin Vincent Necesario
//Note: The symbol-key didn't appear to be part of the object
直接访问 Symbol 属性
但是,我们可以通过 `[]` 令牌访问包含 Symbol 的内容。
console.log("customer[customerSymbol] is equals to " + customer[customerSymbol].getFullYear());
//output: customer[customerSymbol] is equals to 2020
但是,当然,还有另一种方法可以直接通过使用 `Object.getOwnPropertySymbols()` 方法来访问 Symbol。
console.log(Object.getOwnPropertySymbols(customer));
输出
Symbol.for 方法
基本上,`Symbol` 对象维护一个键/值的注册表,其中键是描述,值是 Symbol。现在,当使用 `Symbol.for` 方法时,它会被添加到注册表中,并且该方法会返回 Symbol。因此,如果我们尝试创建一个具有现有描述的 Symbol,它将被检索。
//create a symbol using for method
const mySymbolFor = Symbol.for("My Unique Description");
let product = {
name: "Toyota",
[mySymbolFor]: "Toyota Hilux G"
};
const mySymbolFor2 = Symbol.for("My Unique Description");
console.log(mySymbolFor === mySymbolFor2); //output:true
防止属性名冲突
现在,你已经走到了这一步。你可能已经在实际使用 JavaScript Symbol 了。你可能在想:“有什么好处?”
实际上,它们在库希望向对象添加属性而没有名称冲突风险的情况下很有用。
摘要
- 当你尝试使用新实例时,Symbol 是使用 `Symbol()` 函数调用的,否则将抛出错误。
- JavaScript Symbols 始终是唯一的。
- Symbol 的描述专门用于调试,具有相同描述并不意味着 Symbol 是等价的。
- 如果你想将 JavaScript Symbols 转换为 `string`,则需要显式转换。
- JavaScript Symbols 可用于对象属性中,以防止属性名称冲突。
- `Symbol.for` 具有用于键值对的表注册,它会检索现有的 Symbol 描述,否则会创建一个新的。
希望您喜欢这篇文章,就像我喜欢写它一样。请继续关注更多内容。下次再见,祝您编程愉快!
历史
- 2020 年 7 月 31 日:初始版本