引入Symbol的原因
由于ES5中对象的属性名都是字符串,容易造成属性名的重名冲突,所以ES6引入独一无二的Symbol值防止属性名冲突
Symbol的两种创建方法
1. Symbol()函数
使用Symbol()
函数创建的值不会有重复,每一个都是独一无二的,其类型是symbol
const s1 = Symbol();
console.log(typeof s1); // symbol
Symbol()
函数也可以接收字符串参数,作为Symbol实例的描述,但是两个同名的还是独一无二的值
let s2 = Symbol("xx");
let s3 = Symbol("xx");
console.log(s2 === s3); // false
2. Symbol.for()函数
使用Symbol.for()
函数创建的会首先在全局命名空间里寻找指定参数的值,没有则创建一个,有则返回
注意:这里Symbol.for()
里的参数必须传
let s4 = Symbol.for("xiaoxu");
let s5 = Symbol.for("xiaoxu");
console.log(s4 === s5); // true
注意:Symbol值不能与其他类型的值进行运算,会报错;但是Symbol值可以显示的转为字符串
Symbol创建对象属性
第一种,用方括号[Symbol()]
来表示对象的属性名
第二种,用Object.defineProperty(object, Symbol(), {value})
方法来创建
注意:Symbol值作为对象属性时,不能用点运算符
Symbol属性名的遍历
当Symbol值作为属性名,遍历对象的时候,该属性不会出现在for...in
、for...of
循环遍历中
也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
等返回
只能通过Object.getOwnPropertySymbols()
方法获取指定对象的所有Symbol属性名,或者Reflect.ownKeys()
方法返回所有类型的属性名,包括常规键名和Symbol键名
Symbol的内置属性
Symbol内置属性太多,简单举两个例子
第一个:Symbol.hasInstance
:执行intanceof
时触发
class Person {
static [Symbol.hasInstance](params) {
console.log(params);
console.log("我用来检测类型了");
return false;
}
}
const p = {
name: "p"
};
console.log(p instanceof Person); // 输出log
第二个:Symbol.isConcatSpreadable
:是否展开,执行concat时触发
const arr = [1, 2, 3];
const arr2 = [4, 5, 6];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2)); // [1,2,3,[4,5,6]]