Symbol
Symbol 是一个符号对象,是es6新添加的数据类型,通过Symbol()可以得到一个唯一的值,所以这个值很适合做标识符用。
1. 概述
Symbol的唯一性
Symbol值通过Symbol()函数生成,每个Symbol值是独一无二的。如
let s = Symbol();
let m = Symbol();
console.log(m==s);//false
Symbol函数的参数
Symbol函数可以接受一个字符串作为参数,表示Symbol实例的描述,这个参数的目的是区分不同的Symbol
如:
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
如果上面两个Symbol值不加参数的话,那么输出的都是Symbol() 这样就难以区分了,但加上参数后就相当于为他们取了名字,这样就可以分开了。
注意::
- 即使你设置的参数是一样的,两个不同地点Symbol也是不同的,这就好比我们经常有人撞名字,同名同姓,但他们是不同的人。每个Symbol值就和人一样,都是独一无二的。
- 如果你的参数是一个对象,那么会自动调用对象的tostring()方法,返回的值则作为描述这个Symbol值的参数
const obj = {
toString() {
return 'abc';
}
};
const sym = Symbol(obj);
sym // Symbol(abc)
- Symbol() function 返回一个类型为symbol的值,Symbol有静态属性,原型上也有methods,但是缺少constructor,所以你不能
new Symbol()
来执行;(简单来说是因为Symbol()函数生成的是Symbol数据类型的值,而不是对象,所以不能用new
)
Symbol值的运算和转化
-
Symbol值不能与其他类型的值进行运行,否则会报错。
let sym = Symbol('My symbol'); "your symbol is " + sym // TypeError: can't convert symbol to string `your symbol is ${sym}` // TypeError: can't convert symbol to string
-
Symbol可以转为字符串类、布尔值,但不可以转为数值。
let sym = Symbol('My symbol'); String(sym) // 'Symbol(My symbol)' sym.toString() // 'Symbol(My symbol)'
let sym = Symbol(); Boolean(sym) // true !sym // false if (sym) { // ... } Number(sym) // TypeError sym + 2 // TypeError
作为属性名的Symbol
由于Symbo值是独一无二的,所以它特别适合做标识符,从而用来做对象的属性名,这样可以·防止同名属性的出现。
Symbol作为对象属性名
写法
let mySymbol = Symbol();
\\ 第一种写法
a[mySymbol] = 'Hello!';
\\第二种写法
let a = {
[mySymbol] : 'Hello!'
};
\\ 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!'});
\\ 以上写法都得到同样结果
a[mySymbol] \\ "Hello"
注意:
- 这个时候,Symbol值作为对象名时,不能用点运算符。这是因为点运算符后面的部分都当成了字符串,而不是一个Symbol,所以,要调用Symbol值时,一定要用方括号。
- Symbol值也常用作常量,这时可以起到消除魔术字符串的作用
Symbol值的遍历方法
Symbol作为对象属性名的时候,不能用for...in for...of等方法遍历,要用它设定的方法
object.getOwnPropertySymbols方法
作用:可以返回指定对象的所有Symbol属性名
返回值:一个数组,成员是当前对象的所有用作属性名的Symbol值
例子:
const obj = {};
let foo = Symbol("foo");
Object.defineProperty(obj, foo, {
value: "foobar",
});
for (let i in obj) {
console.log(i); // 无输出
}
Object.getOwnPropertyNames(obj)
// []
Object.getOwnPropertySymbols(obj)
// [Symbol(foo)]
Reflect.ownKeys方法
作用:返回所有类型的键名,包括常规键名和Symbol键名
用法:可以用在创建一些非私有的内部方法。
Symbol.for(),Symbol.keyFor()
Symbol.for()
参数:接受一个字符串当参数
作用:把Symbol值登记在全局环境中供搜索,当有相同参数的Symbol值存在时,则会返回这个Symbol值的调用,没有的话,就会创建一个新的以给定参数的Symbol值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
与Symbol()的区别:Symbol.for()会寻找之前的,而Symbol()一直创建新的Symbol值,如调用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值
Symbol.hasInstance
对象的Symbol.hasInstance属性,指向一个内部方法。当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。比如,foo instanceof Foo在语言内部,实际调用的是Foo[Symbol.hasInstance](foo)
。
Symbol.isConcatSpreadable
对象的Symbol.isConcatSpreadable属性等于一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开。
数组中:Symbol.isConcatSpreadable为true/undefined表示可以展开,false时则不能。
let arr1 = ['c', 'd'];
['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
arr1[Symbol.isConcatSpreadable] // undefined
let arr2 = ['c', 'd'];
arr2[Symbol.isConcatSpreadable] = false;
['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']
类似数组的对象中,则默认不可以展开,必须要设置为true
Symbol.species
对象的Symbol.species属性,指向一个构造函数。创建衍生对象时,会使用该属性。
主要用途:有些类库是在基类的基础上修改的,那么子类使用继承的方法时,作者可能希望返回基类的实例,而不是子类的实例
Symbol.match
作用:对象的Symbol.match属性,指向一个函数。当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值。
Symbol.replace
作用:对象的Symbol.replace属性,指向一个方法,当该对象被String.prototype.replace方法调用时,会返回该方法的返回值。
参数:第一个参数是replace方法正在作用的对象,第二个参数是替换后的值。
Symbol.search
对象的Symbol.search属性,指向一个方法,当该对象被String.prototype.search方法调用时,会返回该方法的返回值。
Symbol.split
对象的Symbol.split属性,指向一个方法,当该对象被String.prototype.split方法调用时,会返回该方法的返回值。
Symbol.iterator
对象的Symbol.iterator属性,指向该对象的默认遍历器方法。对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器。
Symbol.toPrimitive
对象的Symbol.toPrimitive属性,指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。
参数:
- Number:该场合需要转成数值
- String:该场合需要转成字符串
- Default:该场合可以转成数值,也可以转成字符串
Symbol.toStringTag
对象的Symbol.toStringTag属性,指向一个方法。在该对象上面调用Object.prototype.toString方法时,如果这个属性存在,它的返回值会出现在toString方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制[object Object]或[object Array]中object后面的那个字符串。
例子:
// 例一
({[Symbol.toStringTag]: 'Foo'}.toString())
// "[object Foo]"
// 例二
class Collection {
get [Symbol.toStringTag]() {
return 'xxx';
}
}
let x = new Collection();
Object.prototype.toString.call(x) // "[object xxx]"
Symbol.unscopables
对象的Symbol.unscopables属性,指向一个对象。该对象指定了使用with关键字时,哪些属性会被with环境排除。
参考-es6-阮一峰