关于 JS 中的 Symbol 变量类型的一些想法

ECMAScript 6 中新的变量类型 Symbol[1],挺有意思的。以前只是看了几下,但没怎么使用。乘着空闲,研究了一下。

Symbol 最重要的特性就是它的唯一性。你无法初始化同样的 Symbol 变量,这点跟对象是一样的。

1
2
3
4
5
6
7
8
9
10
11
const sb1 = Symbol('symbol')
const sb2 = Symbol('symbol')
sb1 === sb2 // false
const obj1 = {}
const obj2 = {}
obj1 === obj2 // false

Symbol 还可以用作对象中的属性名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const prop_value = Symbol('value')
const prop_plus = Symbol('plus')
const calc = {
[prop_value]: 0,
[prop_plus] (val) {
return this[prop_value] += val
},
}
calc[prop_plus](10)
calc[prop_plus](7)
console.log(calc[prop_value]) // output: 17

注意,此时 calc 对象中 prop_valueprop_plus 都不是字符串类型的属性名。而是 Symbol 类型的。并且 Object.keys() 无法获得 Symbol 值。for in 也无法遍历,Object.getOwnPropertyNames()JSON.stringify() 亦如此。[2]

1
2
3
4
5
6
7
8
9
10
11
12
13
console.log( Object.keys(calc) ) // output: []
const obj_keys = []
for (let key in calc) {
obj_keys.push( key )
}
console.log( obj_keys ) // output: []
console.log( Object.getOwnPropertyNames(calc) ) // output: []
console.log( JSON.stringify( calc ) ) // output: "{}"

Symbol 属性支持原型链。有意思的是 Object.assign 能「取得」Symbol 属性。

1
2
3
4
5
6
7
const calc_chain = Object.create(calc)
console.log(calc_chain[prop_value]) // output: 17
const calc_mixin = Object.assign({}, calc)
console.log(calc_mixin[prop_value]) // output: 17
console.log(calc_mixin === calc) // output: false

因为常规方法无法获得 Symbol 属性。所以我想到可以做到「私有属性」的作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const new_calc = (function () {
const prop_value = Symbol('value')
return {
[prop_value]: 0,
reset () {
this[prop_value] = 0
},
plus (val) {
return this[prop_value] += Number(val)
},
get () {
return this[prop_value]
},
}
})()

因为在匿名函数外部无法获取 prop_value,所以无法在外部修改 new_calc[prop_value] 的值。


  1. 不知道怎么翻译 ↩︎

  2. 使用 Reflect.ownKeys 可以取得 Symbol 属性。Object.getOwnPropertySymbols() 则是只获取 Symbol 属性。 ↩︎