Symbol ———【一天一个 es6 语法】

什么是 Symbol?

1
let 😻 = 😺 × 😍;  // SyntaxError

(爆笑)这当然不是 Symbol。

  • Undefined
  • Null
  • Boolean
  • Number
  • String
  • Object
  • Symbol (ES2015 新增)

Symbol 不是字符串,不是对象,是第七种原始数据类型。每个从Symbol()返回的 symbol 类型的值都是唯一的。一个 symbol 类型的值能作为对象属性的标识符;这是该数据类型仅有的目的

基本语法

通过以下代码就创建一个 Symbol 类型的值。

1
2
3
4
// Symbol([description])
let s = Symbol("我就是我");
typeof s;
// "symbol"

Symbol 中的参数对程序无实际意义,仅供调试助记。不支持语法: new Symbol()

不能自动转换为字符串:

1
2
3
4
5
let s = Symbol();
console.log(" your symbol is" + s);
// TypeError: can't convert symbol to string
console.log(`your symbol is ${s}`)
// TypeError: can't conver symbol to string

应用场景

对象中的私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
let cat = Symbol("cat")
let dog = Symbol("dog")
let pig = Symbol("pig")

const obj = { property: "这是一个动物乐园", [cat]: "金点渐层猫", [dog]: "二哈", [pig]: "藏香猪" }

for (let prop in obj) {
console.log(prop + ": " + obj[prop]
}
// 打印出 property: "这是一个动物乐园"

console.log(Object.getOwnPropertySymbols(obj))
// 打印出 [ Symbol(cat), Symbol(dog), Symbol(pig) ]

基于 symbol 的私有属性对 Object.entriesObject.keysfor...in 等其它迭代器是不可见的。

symbol 属性对 JSON.stringify 方法也是不可见的额。

类中的私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
const _items = Symbol('stackItems');

interface Stack {
[_items]: any[];
}

class Stack {
constructor() {
this[_items] = [];
}
// 添加一个新元素到栈顶
push(element:any){
this[_items].push(element);
}
// 移除栈顶的元素,同时返回
pop() {
return this[_items].pop();
}
// 返回栈顶的元素
peek() {
return this[_items][this[_items].length - 1];
};
// 没有任何元素true,否则false
isEmpty() {
return this[_items].length === 0;
}
// 移除栈里的所有元素
clear() {
this[_items] = [];
}
// 返回栈里的元素个数
size() {
return this[_items].length;
}

print() {
console.log(this.toString());
}

toString() {
return this[_items].toString();
}
}

function getSymbol(){
const stack = new Stack();
return Object.getOwnPropertySymbols(stack);
}

function testSymbol() {
const stack = new Stack();
return stack[_items];
}

console.log(testSymbol());
// []
console.log(getSymbol()[0]);
// Symbol(stackItems)

注意区别 stack[_items]stack['_items']

前者是访问属性名为 Symbol 的特殊方式。
后者是访问一般属性的方法与 stack._items 相同。

我猜测正因为这种特殊的访问方式使其无法通过for...infor...ofObject.keys() 等方法枚举。

通过 testSymbol() 方法在我看来,其并不能达到实现私有变量的目的,仅仅使属性名或方法名不与别人提供的对象产生冲突。是一种保证每个属性名独一无二的方式。


参考文献