Symbol
什么是Symbol
ES6引入了一种新的原始型数据类型 Symbol
,表示独一无二的值。它是JacaScript
的第七中数据类型(现在JavaScript的数据类型:String、Number、Boolean、undefined、null、Symbol、Object)。
为什么要引入Symbol
ES6前所有对象的属性名都是字符串,如果你使用了别人的一个对象,又想为这个对象添加方法时,新方法的方法名就可能和原有方法的名字冲突。ES6中的Symbol值表示独一无二的值,如果属性名使用Symbol值就从根本上杜绝了这种冲突。
创建一个Symbol值
let sym = Symbol();
typeof(sym); //Symbol
注意:创建Symbol值不能使用
new
命令,Symbol是一个原始型类型的值,不是对象。
Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者都转为字符串时,比较容易区分。
let sym1 = Symbol('sym1')
let sym2 = Symbol('sym2')
sym1.toString() // "Symbol(sym1)"
sym2.toString() // "Symbol(sym2)"
如果Symbol的参数是一个对象,就会立即调用对象的toString
方法,将它专为字符串,然后在生成Symbol值。
注意:
- Symbol函数的参数只是表示对当前Symbol值的描述,因此相同参数的Symbol函数的返回值是不相等的
- Symbol值不能与其他类型的值进行运算
- Symbol 值可以显式转为字符串和布尔值,但是不能转换为数值
Symbol.prototype.description
为了能够方便的读取Symbol的描述添加了一个实例方法Symbol.prototype.dedcription
let sym = Symbol(sym1);
sym.description //sym1
Symbol值作为属性名
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上写法都得到同样结果
a[mySymbol] // "Hello!"
注意,Symbol 值作为对象属性名时,不能用点运算符。
let mySymbol = Symbol("HiSymbol");
let mySymbolFun = Symbol("HiSymbolFun");
let a = {};
a.string1 = 'string1!';
a['string2'] = 'string2!'
// a: {string1: "string1!", string2: "string2!"}
//以上两种写法是字符串作为属性名给对象添加属性时的两种写法
a[mySymbol] = "myFirstSymbol"
// a: {string1: "string1!", string2: "string2!", Symbol(HiSymbol): "myFirstSymbol"}
//加中括号,此为Symbol类型作为属性名赋值和取值时的正确写法
//同理在对象内部使用Symbol定义属性、对象调用方法时,也都要放在中括号中,不能使用.操作
let obj = {
[mySymbol]:"Hello Symbol !",
[mySymbolFun]:function(){
console.log(this[mySymbol])
},
};
obj[mySymbolFun]();
// Hello Symbol !
注意:
- 使用Symbol类型时要避免使用
.
操作符,基本上都要使用[ ]
- Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。
Symbol作为属性名被遍历的时候不会出出现在for...in
、for...of
循环中也不会被Obgect.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回。
但是,它也不是私有属性,有一个Object.getOwnPropertySymbols()
方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
let obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
obj['c'] = 'ccHello';
obj.d = 'ddWorld';
for (let i in obj) {
console.log(i);
}
// c
// d
console.log(obj);
// {c: "ccHello", d: "ddWorld", Symbol(a): "Hello", Symbol(b): "World"}
Object.getOwnPropertySymbols(obj);
// [Symbol(a), Symbol(b)]
Symbol.for(),Symbol.keyFor()
有时,我们希望重新使用同一个 Symbol 值,Symbol.for()
方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
上面代码中,s1
和s2
都是 Symbol 值,但是它们都是由同样参数的Symbol.for
方法生成的,所以实际上是同一个值。
Symbol.for()
与Symbol()
这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()
不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key
是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for("cat")
30 次,每次都会返回同一个 Symbol 值,但是调用Symbol("cat")
30 次,会返回 30 个不同的 Symbol 值。
Symbol.keyFor()
方法返回一个已登记的 Symbol 类型值的key
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
注意,
Symbol.for()
为 Symbol 值登记的名字,是全局环境的,不管有没有在全局环境运行。
内置的 Symbol 值
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。
Symbol.hasInstance
对象的Symbol.hasInstance
属性,指向一个内部方法。当其他对象使用instanceof
运算符,判断是否为该对象的实例时,会调用这个方法。
Symbol.isConcatSpreadable
对象的Symbol.isConcatSpreadable
属性等于一个布尔值,表示该对象用于Array.prototype.concat()
时,是否可以展开
Symbol.species
对象的Symbol.species
属性,指向一个构造函数。创建衍生对象时,会使用该属性。
Symbol.match
对象的Symbol.match
属性,指向一个函数。当执行str.match(myObject)
时,如果该属性存在,会调用它,返回该方法的返回值。
Symbol.replace
对象的Symbol.replace
属性,指向一个方法,当该对象被String.prototype.replace
方法调用时,会返回该方法的返回值。
Symbol.search
对象的Symbol.search
属性,指向一个方法,当该对象被String.prototype.search
方法调用时,会返回该方法的返回值。
Symbol.split
对象的Symbol.split
属性,指向一个方法,当该对象被String.prototype.split
方法调用时,会返回该方法的返回值。
Symbol.iterator
对象的Symbol.iterator
属性,指向该对象的默认遍历器方法。
Symbol.toPrimitive
对象的Symbol.toPrimitive
属性,指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。
Symbol.toStringTag
对象的Symbol.toStringTag
属性,指向一个方法。在该对象上面调用Object.prototype.toString
方法时,如果这个属性存在,它的返回值会出现在toString
方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制[object Object]
或[object Array]
中object
后面的那个字符串。
Symbol.unscopables
对象的Symbol.unscopables
属性,指向一个对象。该对象指定了使用with
关键字时,哪些属性会被with
环境排除。
具体使用方法请看下方链接
ES6入门-阮一峰 Symbol章节学习笔记总结