2.13.Symbol ***
2.13.1.Symbol基本定义
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。
它可以用作对象属性的键,用于创建私有属性和方法,以及用于创建唯一的标识符等。
Symbol 值通过内置的 Symbol
函数来创建,并且每个 Symbol
值都是唯一的,不会重复。这意味着任何两个 Symbol
值都不相等。
它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
//创建Symbol
// let s = Symbol();
// console.log(s, typeof s); // 输出 : Symbol() 'symbol'
// 描述只是作为可选参数提供的一个字符串,仅用于调试和标识目的,并不影响 Symbol 的唯一性。
let s2 = Symbol('独一无二的');
let s3 = Symbol('独一无二的');
console.log(s2 === s3); // false
2.13.2.Symbol 的特点
2.13.2.1.防止对象属性名冲突
Symbol 的值是唯一的,用来解决命名冲突的问题
const mySymbol = Symbol('myKey');
const obj = {};
// 可以避免与(可能存在的)原属性myKey 冲突
obj[mySymbol] = 'Hello, Symbol!';
console.log(obj[mySymbol]); // 输出: "Hello, Symbol!"
在这个例子中,我们使用 Symbol
作为对象属性名,由于 Symbol
的唯一性,即使在其他地方也定义了名为 myKey
的 Symbol
,它们也是互不干扰的。
注 : 遇到唯一性的场景时要想到 Symbol
2.13.2.2.Symbol 值不能与其他数据进行运算, 报错
let s = Symbol();
let result = s + '100'; // Uncaught TypeError: Cannot convert a Symbol value to a string
let result = s + 100; // Uncaught TypeError: Cannot convert a Symbol value to a number
let result = s > 100; // Uncaught TypeError: Cannot convert a Symbol value to a number
let result = s + s; // Uncaught TypeError: Cannot convert a Symbol value to a number
2.13.2.3.( ES 10 ) description属性
获取信息
let s = Symbol();
let s2 = Symbol('独一无二的');
console.log(s.description) // undefined
console.log(s2.description) // 独一无二的
2.13.3.Symbol.for()
当你调用 Symbol.for(key)
时,它会检查全局 Symbol
注册表中是否存在以 key
为键的 Symbol
。如果存在,则返回该 Symbol
;如果不存在,则会在注册表中创建一个新的 Symbol
(其描述为 key
),并将其关联到给定的键,然后返回这个新创建的 Symbol
。
这样做的好处是,即便在不同的模块或者上下文中,只要 Symbol.for()
的参数相同,就会返回同一个 Symbol
实例,这有利于跨模块共享和识别 Symbol。
// //Symbol.for 创建
let s4 = Symbol.for('独一无二的');
let s5 = Symbol.for('独一无二的');
console.log(s4 === s5); // true
2.13.3.创建私有属性和方法
//向对象中添加方法 study eat
let stu = {
name:'王小二',
study: function(){},
eat: function(){}
};
// 声明一个对象
let methods = {
study: Symbol(),
eat: Symbol()
};
stu[methods.study] = function(){
console.log("我努力学习");
}
stu[methods.eat] = function(){
console.log("我饿了就吃!!");
}
console.log(stu);
stu[methods.study]()
stu[methods.eat]()
这段代码的主要目的是在 stu
对象中添加名为 study
和 eat
的方法,
但在添加时不清楚, 对象中是否已经有了这两个方法, 如果直接添加就会覆盖原方法
使用了 Symbol 类型的键来定义这些方法,以实现私有或隐藏属性的效果。
声明了一个名为 methods
的对象,其中包含两个 Symbol 类型的属性:study
和 eat
。
然后,将新的方法赋值给 stu
对象,但是使用了 methods
对象中的 Symbol 键:stu[methods.study]
stu[methods.eat]
这样stu 就有 4个函数 study
, eat
, stu[methods.study]
, stu[methods.eat]
在控制台输出时,由于 Symbol 键不可枚举,因此我们无法直接看到 methods.study
和 methods.eat
关联的方法。
这种使用 Symbol 创建“私有”方法的方式可以避免外部代码误操作或意外访问到这些方法,增强了代码的安全性和封装性。
若要调用这些方法,需要知道对应的 Symbol 键,例如:stu[methods.study]()
或 stu[methods.eat]()
。
2.13.4.Symbol 内置值***
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。
可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。
2.13.4.1.Symbol.hasInstance
当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法
class Stu{
static [Symbol.hasInstance](param){
console.log(param);
console.log("我被用来检测类型了");
return false;
}
}
let o = {};
console.log(o instanceof Stu);
2.13.4.2.Symbol.iterator
对象进行 for…of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器
let myArray = ['a', 'b', 'c'];
let iterator = myArray[Symbol.iterator]();
iterator.next(); // { value: "a", done: false }
2.13.4.3.Symbol.toPrimitive
该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。
let obj = {
[Symbol.toPrimitive](hint) {
if (hint === 'string') {
return 'converted to string';
}
// ...
}
};
String(obj); // 'converted to string'
2.13.4.4.Symbol.isConcatSpreadable
对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。
const arr = [1,2,3];
const arr2 = [4,5,6];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2));
2.13.4.5.Symbol.species
创建衍生对象时,会使用该属性
2.13.4.6.Symbol.match
当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。
2.13.4.7.Symbol.replace
当该对象被 str.replace(myObject)方法调用时,会返回该方法的返回值。
2.13.4.8.Symbol.search
当该对象被 str.search (myObject)方法调用时,会返回该方法的返回值。
2.13.4.9.Symbol.split
当该对象被 str.split(myObject)方法调用时,会返回该方法的返回值。
2.13.4.10.Symbol. toStringTag
在该对象上面调用 toString 方法时,返回该方法的返回值
2.13.4.11.Symbol. unscopables
该对象指定了使用 with 关键字时,哪些属性会被 with环境排除。