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)里面。let 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
// 使用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中
import Login from './a'
const login = new Login('admin', '123456')
login.checkPassword('123456') // true
login.PASSWORD // oh!no!
login[PASSWORD] // oh!no!
login["PASSWORD"] // oh!no!
由于Symbol常量PASSWORD
被定义在a.js所在的模块中,外面的模块获取不到这个Symbol,也不可能再创建一个一模一样的Symbol出来(因为Symbol是唯一的),因此这个PASSWORD
的Symbol只能被限制在a.js内部使用,所以使用它来定义的类属性是没有办法被模块外访问到的,达到了一个私有化的效果。