前言
在ES6之前,Object对象的属性名只能是字符串,在引用他人提供的对象,并为对象添加新属性的过程中,很容易出现属性名冲突。为了解决这个问题,ES6 引入了一种新的原始数据类型 Symbol。
Symbol表示独一无二的值,最大的用法是用来定义对象的唯一属性名,它是JavaScript的第六种基本数据类型(string、number、boolean、undefined、null、Symbol)。在此之后,对象的属性名可以有两种类型:字符串 / Symbol 。
一、Symbol类型的创建
理解: Symbol 是基本数据类型而并非对象,因此无法通过 new 的方式创建,Symbol可以通过Symbol()函数生成。
// 创建symbol
const symbol =Symbol();
console.log(symbol); // 输出:Symbol()
console.log(typeof(symbol)); // 输出:symbol
参数: Symbol函数接收一个字符串作为参数,用于为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。
const symbol =Symbol("描述");
console.log(symbol); // 输出:Symbol(描述)
注意: Symbol函数的描述只表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。
const symbol1 = Symbol("稀土掘金");
const symbol2 = Symbol("稀土掘金");
console.log(symbol1 === symbol2); // 输出:false
二、Symbol的特点
1. Symbol 的值是唯一的,所以不存在命名冲突
let obj = {
[Symbol("稀土掘金")]: "Very",
[Symbol("稀土掘金")]: "Cool",
};
console.log(obj); // 输出:{Symbol(稀土掘金): 'Very', Symbol(稀土掘金): 'Cool'}
2. Symbol 值不能与其他数据进行运算
const symbol = Symbol("稀土掘金");
const num = 666 + symbol;
const str = "VeryCool" + symbol;
console.log(num); // 输出:Cannot convert a Symbol value to a number
console.log(str); // 输出:Cannot convert a Symbol value to a string
3. Symbol的读取方式
注意: Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问。
但是 Symbol 无法通过
for...in、for...of读取,也不会被Object.keys()、Object.getOwnPropertyNames()返回。
let obj = {
name: "VeryCool",
age: 18,
[Symbol("like")]: "稀土掘金",
};
// for...in
for(let item in obj) {
console.log(item); // 输出: name age 不输出:like
}
// for...of
for(let item of obj) {
console.log(item); // 输出: obj is not iterable
}
// Object.keys()
console.log(Object.keys(obj)); // 输出:['name', 'age']
// Object.getOwnPropertyNames()
console.log(Object.getOwnPropertyNames(obj)); // 输出:['name', 'age']
如果要读取一个对象的 Symbol 属性,可以通过
Object.getOwnPropertySymbols()和Reflect.ownKeys()读取。
let obj = {
name: "VeryCool",
age: 18,
[Symbol("like")]: "稀土掘金",
};
// Object.getOwnPropertySymbols()方法专门用来读取symbol
console.log(Object.getOwnPropertySymbols(obj)); // 输出:[Symbol(like)]
// Reflect.ownKeys()方法可以读取包含symbol的所有属性
console.log(Reflect.ownKeys(obj)); // 输出:['name', 'age', Symbol(like)]
三、Symbol的使用场景
作用: 因为每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,可以保证属性不重名。
const symbol = Symbol();
// 第一种写法
const obj = {};
obj[symbol] = "VeryCool";
// 第二种写法
const obj = {
[symbol]: "VeryCool",
};
// 第三种写法
const obj = {};
Object.defineProperty(obj, symbol, { value: "VeryCool" });
// 以上写法结果都如下
const obj = {
Symbol(): "VeryCool"
}
四、Symbol的API
Symbol.for()
Symbol.for()类似单例模式,首先会在全局搜索被登记的 Symbol 中是否有该字符串参数作为名称的 Symbol 值,如果有即返回该 Symbol 值,若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索。
Symbol.for("bar") === Symbol.for("bar") // true
Symbol("bar") === Symbol("bar") // false
Symbol.keyFor()
Symbol.keyFor() 返回一个已登记的 Symbol 类型值的 key ,用来检测该字符串参数作为名称的 Symbol 值是否已被登记。
const symbol1 = Symbol.for("稀土掘金");
Symbol.keyFor(symbol1); // "稀土掘金"
const symbol2 = Symbol("稀土掘金");
// (变量symbol2属于未登记的 Symbol 值,所以返回undefined)
Symbol.keyFor(symbol2); // undefined
(文章参考自阮一峰ECMAScript 6入门)