Symbol的使用场景
使用Symbol来作为对象属性名(key)
通常定义或访问对象的属性时都是使用字符串:
let obj = {
abc: 123,
"hello": "world"
}
obj["abc"] // 123
obj["hello"] // 'world'
在利用Symbol以后定义和访问对象的属性:
const PROP_NAME = Symbol()
const PROP_AGE = Symbol()
let obj = {
[PROP_NAME]: "君莫笑"
}
obj[PROP_AGE] = 18
obj[PROP_NAME] // '君莫笑'
obj[PROP_AGE] // 18
Symbol类型的key不能通过Object.keys()或者for…in来枚举。它没有被包含在对象自身的属性名集合(property names)里面。
l
et obj = {
[Symbol('name')]: '君莫笑',
age: 18,
title: 'Engineer'
}
Object.keys(obj) // ['age', 'title']
for (let p in obj) {
console.log(p) // 分别会输出:'age' 和 'title'
}
Object.getOwnPropertyNames(obj) // ['age', 'title']
利用这个特性,可以把一些不需要对外操作和访问的属性用Symbol来定义
使用JSON.stringify()将对象转换成JSON字符串时,Symbol属性会被排除在输出内容之外。
JSON.stringify(obj) // {"age":18,"title":"Engineer"}
获取Symbol方式定义的对象属性,专门针对Symbol的API getOwnPropertySymbols
// 使用Object的API
Object.getOwnPropertySymbols(obj) // [Symbol(name)]
// 使用新增的反射API
Reflect.ownKeys(obj) // [Symbol(name), 'age', 'title']
使用Symbol来替代常量
我们经常定义一组常量来代表一种业务逻辑下的几个不同类型,我们通常希望这几个常量之间是唯一的关系,为了保证这一点,我们需要为常量赋一个唯一的值。
比如如下的’AUDIO’、‘VIDEO’、 ‘IMAGE’
const TYPE_AUDIO = 'AUDIO'
const TYPE_VIDEO = 'VIDEO'
const TYPE_IMAGE = 'IMAGE'
function handleFileResource(resource) {
switch(resource.type) {
case TYPE_AUDIO:
playAudio(resource)
break
case TYPE_VIDEO:
playVideo(resource)
break
case TYPE_IMAGE:
previewImage(resource)
break
default:
throw new Error('Unknown type of resource')
}
}
在使用Symbol定义常量以后就会相当方便
const TYPE_AUDIO = Symbol()
const TYPE_VIDEO = Symbol()
const TYPE_IMAGE = Symbol()
这样可以直接保证三个常量的值是唯一的。
使用Symbol定于类的私有属性/方法
JS中没有访问控制关键字。类上所有定义的属性或者方法都是可以公开的。使用Symbol,再加上模块化机制以后,类的私有属性和方法才能变成可能;
在文件a.js中
const PASSWORD = Symbol()
class Login {
constructor(username, password) {
this.username = username
this[PASSWORD] = password
}
checkPassword(pwd) {
return this[PASSWORD] === pwd
}
}
export default Login
在文件b.js中
const login = new Login('admin', '123456')
login.checkPassword('123456') // true
login.PASSWORD // oh!no!
login[PASSWORD] // oh!no!
login["PASSWORD"] // oh!no!
9
由于Symbol常量PASSWORD被定义在a.js所在的模块中,外面的模块获取不到这个Symbol,也不可能再创建一个一模一样的Symbol出来(因为Symbol是唯一的),因此这个PASSWORD的Symbol只能被限制在a.js内部使用,所以使用它来定义的类属性是没有办法被模块外访问到的,达到了一个私有化的效果。