【ES6】Symbol 基本数据类型
Symbol - 作为对象属性的标识符
8种数据类型:
-
7种值类型(基本数据类型): Number , String , Boolean , null , undefined , Symbol , BigInt
-
1种引用数据类型: Object
Symbol 表示独一无二的值
一个symbol值能作为对象属性的标识符,这是该数据类型仅有的目的。
Symbol 值通过 Symbol 函数生成。
let s = Symbol();
typeof s; // "symbol"
注意,Symbol 函数前不能使用 new 命令,否则会报错。它是一种类似于字符串的数据类型。 Symbol 值不是一个对象,不能添加属性。
Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述。这只是为了容易区分。如果参数是一个对象,将会调用该对象的 toString() 方法将其转为字符串,然后才生成一个 Symbol 值。
let a = Symbol();
let b = Symbol();
console.log(a === b); // false(参数只是为了更好地区分,即使是没有参数,两个返回值也是不同的,Symbol 表示的是唯一值)
Symbol 值不能与其他类型的值进行运算,会报错。
let s = Symbol("My Symbol");
console.log(`your symbol is ${s}`); // 报错
Symbol 值不能隐式转为字符串,但是可以显式转换。Symbol 值也可以转为 Boolean ,但是不能转为 Number 。
// 显式转为字符串:
let s = Symbol("My Symbol");
String(s); // "Symbol(My Symbol)"
s.toString(); // "Symbol(My Symbol)"
// 显式转为 Boolean :
let s2 = Symbol();
Boolean(s2); // true
console.log(!s2); // false
读取 Symbol 实例的描述,需要将 Symbol 显式转为字符串,也可以通过实例属性 description 直接返回 Symbol 的描述。
const s = Symbol("这是描述");
console.log(s.description); // 这是描述
Symbol 值可以作为标识符,用于对象的属性名,这样子可以保证不会出现同名的属性。
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上写法都得到同样结果
a[mySymbol] // "Hello!"
上面代码中,通过方括号结构和 Object.defineProperty ,将对象的属性名指定为一个 Symbol 值。
Symbol 值作为对象属性名时,不能用点运算符。在对象内部使用 Symbol 值定义属性时(该属性是公开属性),Symbol 值必须放在方括号中。
const sym1 = Symbol();
const sym2 = Symbol();
let a = {};
// 情况一:使用 []
a[sym1] = "Hi"; // sym1 放在方括号中,是以 Symbol 值来定义属性的
console.log(a[sym1]); // Hi(在对象 a 中存在一个以 Symbol 值定义的对象属性名 sym1)
console.log(a.sym1); // undefined(在对象 a 中不存在属性 sym1 )
console.log(a['sym1']); // undefined(在对象 a 中不存在属性 sym1 )
// 情况二:使用点运算符
a.sym2 = "Hello"; // sym2 放于点运算符后,是以字符串 sym2 作为标识符存在的,而不是之前定义的 Symbol 值:sym2
console.log(a.sym2); // Hello(在对象 a 中存在属性 sym2 , 值为 "Hello" )
console.log(a['sym2']); // Hello(在对象 a 中存在属性 sym2 , 值为 "Hello" )
console.log(a[sym2]); // undefined(在对象 a 中不存在一个以 Symbol 值定义的对象属性名 sym2)
上面代码中,因为点运算符后总跟着字符串标识符,所以点运算符后的 sym2 是作为对象的标识符存在的,而不是一个 Symbol 值。
遍历
Symbol 作为属性名,遍历对象的时候,该属性不会出现在 for...in 、for...of 循环中,也不会被 Object.keys() 、Object.getOwnPropertyNames() 、JSON.stringify() 返回。
但是,它也不是私有属性,有一个 Object.getOwnPropertySymbols() 方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
Reflect.ownKeys() 方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
由于以 Symbol 值作为键名,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
Symbol.for()
接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
console.log(s1 === s2); // true
上面代码中,s1和s2都是 Symbol 值,但是它们都是由同样参数的 Symbol.for 方法生成的,所以实际上是同一个值。
与 Symbol 的区别是:Symbol.for 会被登记在全局环境中供搜索,而 Symbol 不会。
Symbol.keyFor()
返回一个已登记的 Symbol 类型值的 key 。
let s1 = Symbol.for("foo");
Symbol.keyFor(s1); // "foo"

浙公网安备 33010602011771号