创建Symbol
let a = Symbol()
let b = Symbol('b')
let person = {
[a]: 'one',
[b]: 'oneday',
}
console.log(person[a]) // one
console.log(a) // Symbol()
console.log(person[b]) // oneday
console.log(b) // Symbol(b)
可以使用typeof操作符来获得变量的属性:
typeof a // "symbol"
如果想在不同的对象中共享一个Symbol,可以使用Symbol.for()
:
let a = Symbol.for('a')
let b = Symbol.for('a')
let person = {
[a]: 'one',
}
console.log(a === b) // true
console.log(person[a]) // a
console.log(person[b]) // a
Symbol.for()
方法首先在全局Symbol注册表中搜索键为'one'的Symbol是否存在,如果存在,直接返回已有的Symbol值,否则会创建一个新的Symbol并在Symbol的注册表中注册,然后返回该新创建的Symbol。如上,a和b可以互换。
Symbol.keyFor()
方法在Symbol全局注册表中检索与Symbol有关的键:
console.log(Symbol.keyFor(a)) // one
console.log(Symbol.keyFor(b)) // one
let c = Symbol('a')
console.log(Symbol.keyFor(c)) // undefined
不能将Symbol强制转换为字符串和数字类型。
Object.keys()
方法和Object.getOwnPropertyNames()
方法可以检索对象中所有的属性名:前一个返回所有可枚举的属性名;后一个方法不考虑属性的可枚举性一律返回。而想要枚举Symbol属性则需要一个新的方法:Object.getOwnPropertySymbols()
,会返回一个包含对象所有Symbol属性的数组:
let a = Symbol('a')
let b = Symbol('b')
let c = Symbol('c')
let person = {
[a]: 'one',
[b]: 'day',
[c]: 'oneday'
}
let arr = Object.getOwnPropertySymbols(person)
console.log(arr) // (3) [Symbol(a), Symbol(b), Symbol(c)] 0: Symbol(a) 1: Symbol(b) 2: Symbol(c)
Symbol.hasInstance
用于确定对象是否为函数的实例。不可写、不可配置并且不可枚举。
arr instanceof Array
相当于Array[Symbol.hasInstance](obj)
。
可以通过Symbol.hasInstance
设置为false手动将一个函数设置为“无实例”的(其实是实例,只是返回了false)。
function MyObject() {}
Object.defineProperty(MyObject, Symbol.hasInstance, {
value: function(v) {
return false
}
})
let obj = new MyObject()
console.log(obj instanceof MyObject) // false
Symbol.isConcatSpreadable
一个布尔值,如果该属性为true,则表示对象有length属性和数字键,故它的数值型属性值应该被独立添加到concat()
调用的结果中。是一个可选属性。
let collection = {
0: 'hello',
1: 'world',
length: 2,
[Symbol.isConcatSpreadable]: true
}
let message = ['hi']
let a = message.concat(collection)
console.log(a) // (3) ["hi", "hello", "world"]
如果不设置该属性或设置为false,则结果为(2) ["hi", {…}]
。
Symbol.match
、Symbol.replace
、Symbol.search
和Symbol.split
都会在调用String.prototype.xxx函数时被调用。
Symbol.match
:接受一个字符串类型的参数,如果匹配成功则返回匹配元素的数组,否则返回null;Symbol.replace
:接受一个字符串类型的参数和一个替换用的字符串,最终依然返回一个字符串;Symbol.search
:接受一个字符串参数,如果匹配到内容,则返回数字类型的索引位置,否则返回-1;Symbol.split
:接受一个字符串参数,根据匹配内容将字符串分解,并返回一个包含分解后片段的数组。Symbol.iterator
一个返回迭代器的方法。Symbol.species
一个用于创建派生类的构造函数。Symbol.toPrimitive
返回对象原始值。
JavaScript中,执行特定操作时,经常会尝试将对象转换为相应的原始值,例如比较一个字符串和一个对象,如果使用双等号(==)运算符,对象会在比较操作前被转换为一个原始值。
对于大多数标准对象,数字模式有以下特性,根据优先级的顺序排列如下:
- 调用
valueOf()
方法,如果结果为原始值,则返回; - 否则,调用
toString()
方法,如果结果为原始值,则返回; - 如果再无可选值,则抛出错误。
对于大多数标准对象,字符串模式有以下特性,根据优先级的顺序排列如下:
- 调用
toString()
方法,如果结果为原始值,则返回; - 否则,调用
valueOf()
方法,如果结果为原始值,则返回; - 如果再无可选值,则抛出错误。
如果自定义Symbol.toPrimitive方法,则可以覆盖这些默认的强制转换特性。
function Temperature(degree) {
this.degree = degree
}
Temperature.prototype[Symbol.toPrimitive] = function(hint) {
switch(hint) {
case 'string':
return this.degree + '\u00b0'
case 'number':
return this.degree
case 'default':
return this.degree + ' degrees'
}
}
var freezing = new Temperature(27)
console.log(freezing + '!') // 27 degrees!
console.log(freezing / 2) // 13.5
console.log(String(freezing)) // 27°
hint在这里作为类型提示参数,类型提示参数的值只有三种选择:'number'、'string'或'default'。传递这些参数时,Symbol.toPrimitive返回的分别是数字、字符串或无类型的值。所以上例中,+触发default模式,/运算符触发数字模式,String触发字符串模式。
Symbol.toStringTag
可以改变调用Object.prototype.toString()
返回的身份标识。
经常会遇到问怎么判断一个数组是不是一个数组的问题,因为typeof []
返回object
,所以就有了这样的方法:
Object.prototype.toString.call([]) // [object Array]
但是[Symbol.toStringTag]
可以改变这个返回值,如下:
Array.prototype[Symbol.toStringTag] = 'Oneday'
Object.prototype.toString.call([]) // [object Oneday]
所以不要用这个特性去更改内建对象。
Symbol.unscopables
通常用于Array.prototype,以在with语句中表示出不创建with绑定的属性名。Symbol.unscopables是以对象的形式出现的,它的键是在with语句中要忽视的标识符(函数名),其对应的值必须是true。例如:
Array.prototype[Symbol.unscopables] = Object.assign(Object.create(null), {
copyWithin: true,
entries: true,
fill: true,
find: true,
findIndex: true,
keys: true,
values: true
})