一、Symbol类型
symbol 是一种基本数据类型 (primitive data type)。每个从Symbol()
返回的symbol值都是唯一的。
不支持语法:"new Symbol()
":从 ECMAScript 6 开始不再被支持原始数据类型创建一个显式包装器对象。 然而,现有的原始包装器对象,如 new Boolean
、new String
以及new Number
,因为遗留原因仍可被创建。所以目前只有Symbol类型不能创建包装器对象。
直接使用Symbol()
创建新的symbol类型,并用一个可选的字符串作为其描述。主要是为了在控制台显示,或者转为字符串时,比较容易区分
var sym1 = Symbol();
var sym2 = Symbol('foo');
var sym3 = Symbol('foo');
上面的代码创建了三个新的symbol类型。 注意,Symbol("foo")
不会强制将字符串 “foo” 转换成symbol类型。它每次都会创建一个新的 symbol类型。
注意,Symbol
函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol
函数的返回值是不相等的。
Symbol("foo") === Symbol("foo"); // false
Symbol 值可以显式转为字符串。
let sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'
Symbol 值也可以转为布尔值,但是不能转为数值。
let sym = Symbol();
Boolean(sym) // true
!sym // false
if (sym) {
// ...
}
Number(sym) // TypeError
sym + 2 // TypeError
作为对象的属性,写法上要用[ ]变量的形式
let sym = Symbol();
let obj = {
[sym]: function (arg) {
console.log(arg); //123
}
};
obj[sym](123);
只有上述方式可以操作和获取Symbol键,以下方式不可以:
因为Symbol的唯一性,对象属性的Symbol("foo")和打印的Symbol("foo")属性不是一个
var obj = {
[Symbol("foo")] : 1
}
console.log(obj[Symbol("foo")]);
获取对象的symbol类型的属性名:
Symbol 作为属性名,遍历对象的时候,该属性不会出现在for...in
、for...of
循环中,也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回。
但是,它也不是私有属性,有一个Object.getOwnPropertySymbols()
方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。注意,每个初始化的对象都是没有自己的symbol属性的,因此这个数组可能为空,除非你已经在对象上设置了symbol属性。
const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
const objectSymbols = Object.getOwnPropertySymbols(obj);// [Symbol(a), Symbol(b)]
var sym = Symbol("foo");
var obj = {
[sym] : 1
}
console.log(Object.getOwnPropertyDescriptors(obj));
二、Symbol方法
Symbol.for()
方法和 Symbol.keyFor()
有时,我们希望重新使用同一个 Symbol 值,Symbol.for()
方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。
let sym1 = Symbol.for('foo');
let sym2 = Symbol.for('foo');
sym1 === sym2 // true
Symbol.for()
不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key
是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for("cat")
30 次,每次都会返回同一个 Symbol 值,但是调用Symbol("cat")
30 次,会返回 30 个不同的 Symbol 值。
注意:Symbol.for()的值, symbol 注册表中的值
let sym1 = Symbol.for('foo');
let sym2 = Symbol.for('bar');
console.log(sym1,sym2); Symbol(foo) Symbol(bar)
Symbol.keyFor(sym)
方法用来获取 symbol 注册表中某个 symbol 关联的键
let sym1 = Symbol.for('foo');
let sym2 = Symbol.for('bar');
console.log(Symbol.keyFor(sym1),Symbol.keyFor(sym2)); foo bar
三、Symbol属性
1、Symbol.iterator 为对象定义了默认的迭代器。该迭代器可以被 for...of
循环使用。
当需要对一个对象进行迭代时(比如开始用于一个for..of
循环中),它的@@iterator
方法都会在不传参情况下被调用,返回的迭代器用于获取要迭代的值。
一些内置类型拥有默认的迭代器行为,其他类型(如 Object
)则没有。下表中的内置类型拥有默认的@@iterator
方法:
Array.prototype[@@iterator]()
TypedArray.prototype[@@iterator]()
String.prototype[@@iterator]()
Map.prototype[@@iterator]()
Set.prototype[@@iterator]()
(1)数组
Symbol在对象中存在的形式:
let sym = Symbol("foo");
var obj = {
[sym]: function(){}
}
console.log(obj);
数组中[Symbol.iterator]属性
let arr = [1,2,3];
console.log(arr.valueOf());//数组没有该方法,继承对象的该方法
console.log(arr.values()); //ES6新增方法
console.log(arr[Symbol.iterator]()); //该方法也指向values函数体
结果:iterator对象 ——> Array Iterator对象 ——> Object
(2)字符串
字符串中[Symbol.iterator]属性
let str = new String("abc");
console.log(str[Symbol.iterator]()); //得到iterator对象
结果:该iterator对象 ——> String Iterator对象 ——> Object
(3)Map
(4)Set
Symbol.iterator
Symbol.unscopables