JavaScript基本对象Symbol研究_01_基本介绍_Symbol构造函数_静态方法_Symbol.for()、Symbol.keyFor()
在ES6(ECMAScript 2015)中,Symbol
是一种新的原始数据类型,表示独一无二的值。它是继Number
、String
、Boolean
、Null
、Undefined
之后的第七种数据类型。Symbol
的引入为对象属性名提供了唯一的标识符,避免属性名的冲突,尤其在对象需要扩展时。
本文将深入探讨Symbol
的基本概念、Symbol
构造函数以及重要的静态方法Symbol.for()
和Symbol.keyFor()
,帮助您全面理解Symbol
在JavaScript中的应用。
一、基本介绍
1. 什么是Symbol?
Symbol
是原始数据类型的一种,表示独一无二的值。每个从Symbol()
函数返回的Symbol
值都是唯一的,即使它们的描述(description)相同。
let sym1 = Symbol('foo');
let sym2 = Symbol('foo');
console.log(sym1 === sym2); // 输出: false
2. Symbol的用途
-
作为对象的唯一属性键:使用
Symbol
作为对象的属性名,可以确保属性不被意外覆盖或访问。 -
实现私有属性:通过
Symbol
,可以模拟对象的私有属性,防止外部直接访问。 -
元编程:
Symbol
内置了一些预定义的Symbol
值(如Symbol.iterator
),用于改变语言内部行为,实现迭代器等高级功能。
3. 创建Symbol
创建Symbol
值需要调用Symbol()
函数,不能使用new
关键字,因为Symbol
不是构造函数。
let sym = Symbol('description');
- description(可选):一个字符串,表示对
Symbol
值的描述,主要用于调试和日志记录。
二、Symbol构造函数
1. 基础语法
let sym = Symbol([description]);
- description:对
Symbol
的描述,便于调试。
2. 示例代码
let sym = Symbol('mySymbol');
console.log(sym); // 输出: Symbol(mySymbol)
console.log(typeof sym); // 输出: "symbol"
3. 注意事项
-
Symbol值是唯一的:即使描述相同,
Symbol
值也不相等。 -
Symbol不能与其他类型进行运算:
Symbol
值不能参与算术运算或字符串拼接。let sym = Symbol('test'); console.log(sym + ''); // 报错:Cannot convert a Symbol value to a string
-
转换为字符串:可以使用
String()
函数或symbol.toString()
方法。let sym = Symbol('test'); console.log(String(sym)); // 输出: "Symbol(test)" console.log(sym.toString()); // 输出: "Symbol(test)"
三、Symbol的使用
1. 作为对象属性名
使用Symbol
作为对象的属性名,可以避免属性名的冲突。
let symKey = Symbol('key');
let obj = {
[symKey]: 'value'
};
console.log(obj[symKey]); // 输出: "value"
2. 定义不可枚举的属性
Symbol
属性默认是不可枚举的,不会出现在for...in
、for...of
循环中,也不会被Object.keys()
、Object.getOwnPropertyNames()
返回。
let obj = {};
let sym = Symbol('hidden');
obj[sym] = 'secret';
for (let key in obj) {
console.log(key); // 没有输出
}
console.log(Object.keys(obj)); // 输出: []
console.log(Object.getOwnPropertyNames(obj)); // 输出: []
3. 获取Symbol属性
可以使用Object.getOwnPropertySymbols(obj)
获取对象的所有Symbol
属性。
let sym1 = Symbol('first');
let sym2 = Symbol('second');
let obj = {
[sym1]: 'value1',
[sym2]: 'value2'
};
let symbols = Object.getOwnPropertySymbols(obj);
console.log(symbols); // 输出: [Symbol(first), Symbol(second)]
四、Symbol的静态方法
1. Symbol.for()
1.1 基础介绍
Symbol.for()
方法用于在全局符号注册表中查找或创建一个Symbol
。对于相同的键,Symbol.for()
会返回相同的Symbol
值。
1.2 语法
let sym = Symbol.for(key);
- key:字符串,表示
Symbol
的键。
1.3 示例代码
let sym1 = Symbol.for('shared');
let sym2 = Symbol.for('shared');
console.log(sym1 === sym2); // 输出: true
1.4 使用场景
- 跨文件或模块共享Symbol:使用
Symbol.for()
可以在不同的模块中共享相同的Symbol
值。
1.5 注意事项
- 全局注册表:
Symbol.for()
使用的键在全局范围内有效,可能会导致命名冲突,需要注意键的唯一性。
2. Symbol.keyFor()
2.1 基础介绍
Symbol.keyFor()
方法返回一个从全局注册表中找到的Symbol
的键。
2.2 语法
let key = Symbol.keyFor(sym);
- sym:一个通过
Symbol.for()
注册的Symbol
。
2.3 示例代码
let sym = Symbol.for('shared');
let key = Symbol.keyFor(sym);
console.log(key); // 输出: "shared"
2.4 使用场景
- 获取全局Symbol的键:在需要根据
Symbol
值获取其全局键时,可以使用Symbol.keyFor()
。
2.5 注意事项
-
仅适用于全局Symbol:对于非全局注册的
Symbol
,Symbol.keyFor()
返回undefined
。let localSym = Symbol('local'); console.log(Symbol.keyFor(localSym)); // 输出: undefined
五、示例:Symbol.for()和Symbol()的区别
let localSym1 = Symbol('test');
let localSym2 = Symbol('test');
console.log(localSym1 === localSym2); // 输出: false
let globalSym1 = Symbol.for('test');
let globalSym2 = Symbol.for('test');
console.log(globalSym1 === globalSym2); // 输出: true
console.log(Symbol.keyFor(globalSym1)); // 输出: "test"
console.log(Symbol.keyFor(localSym1)); // 输出: undefined
-
Symbol()
创建的Symbol是局部的,每次都会返回新的唯一值。 -
Symbol.for()
会在全局注册表中查找,如果存在则返回已注册的Symbol,否则创建新的并注册。
六、Symbol的注意事项
-
不能使用
new
关键字:Symbol
不是构造函数,直接调用即可。let sym = new Symbol(); // 报错:Symbol is not a constructor
-
Symbol不能被自动转换为字符串:在字符串拼接或其他需要字符串的地方,需要显式转换。
let sym = Symbol('desc'); console.log('Symbol is ' + sym); // 报错:Cannot convert a Symbol value to a string // 正确方式 console.log('Symbol is ' + String(sym)); // 输出: Symbol is Symbol(desc)
-
Symbol作为对象属性时的访问:需要使用方括号
[]
,不能使用点.
。let sym = Symbol('key'); let obj = { [sym]: 'value' }; console.log(obj[sym]); // 输出: "value"
小结
-
使用
Symbol
可以创建唯一的值,避免属性名冲突。 -
Symbol()
创建的Symbol
是局部的,Symbol.for()
创建的Symbol
是全局注册的。 -
Symbol.keyFor()
可以获取全局Symbol
的键,对于局部Symbol
返回undefined
。 -
Symbol
在对象属性名中的使用需要注意访问方式,使用[]
而不是.
。
参考资料: