最近在恶补JS基础,正好看到了Symbol这块,所以决定记录一下。
我们都知道对象的属性名都是字符串,这就很容易造成属性名字的冲突,导致原有的固有方法被重写(这也叫做mixin混入模式)。
这个时候就需要一种机制,来保证每个属性名字都是独一无二的。Symbol就是这种机制。
let a = symbol();
let b = symbol("foo");
let c = symbol("bar");
我们可以看到,symbol函数里面,参数是可有可无的。参数的作用仅仅是对当前symbol值的描述。
代码实践:
let b1 = 'b1';
let obj1 = {
a: 11,
b: 22,
[Symbol('sty')]: 55,
[b1]: 66
}
obj1.__proto__ = {
c: 33
}
Object.keys(obj1); // 【“a”,“b”,“b1”】
Object.getOwnPropertyNames(obj1); // 【“a”,“b”,“c1”】
Object.getOwnPropertySymbols(obj1); // 【Symbol(sty)】
指向了 instanceOf 的秘密。当我们使用 instanceOf 来检测某某实例时,实际上就是调用的这个方法。
foo instanceOf Foo; // 等价于下面的写法
Foo[Symbol.hasInstance](foo);
表示该对象是否可被 array.concat
方法展开。当此属性值为true时,表示此对象可以被展开。
let arr1 = [1, 2];
arr1[Symbol.isConcatSpreadable] = false;
[].concat(arr1); // 返回:【 【1, 2】 】
let arr2 = { length: 3, 0: 'a', 1: 'b', 2: 'c' };
arr2[Symbol.isConcatSpreadable] = true;
[].concat(arr2); // 返回: [ 'a', 'b', 'c' ]
当一个数据结构拥有了Symbol.iterator属性,那说明它可以被for … of 遍历。反之亦然。
这个方法是干啥的呢?
在这个内置的Symbol属性(Symbol.toPrimitive)的作用下,对象可以转换为一个原始值。
当发生强制类型转换的时候,会自动调用这个方法,这个方法接受一个字符串参数,并且值只能是“string”、“number”、“default”。
let obj = {
a: 22,
[Symbol.toPrimitive](hint){
switch(hint){
case 'number':
return 100;
case 'string':
return '200';
case 'default':
return 'default';
default:
throw new Error('something is wrong');
}
}
};
obj1 == 'default'; // true
(2 * obj1) === 200; // true
我们知道,JS中提供了多种数据类型检测的方法,其中Object.prototype.toString.call这个方法屡试不爽。
原因很简单,相对来说,它是万能油。
typeof 不能检测数组跟null类型;Array.isArray只能用来检测数组;instanceOf只能用来检测引用数据类型。
那么Object.prototype.toString.call方法是如何实现的呢?
答案就是这个内置的Symbol属性。
let obj = {
[Symbol.toStringTag]: "这是一个陌生的属性"
}
Object.prototype.toString.call(obj); // 返回“这是一个陌生的属性”