0%

每天一點點,學習ES6(五)數據結構Symbol

前言

今天要來研究 新增的數據結構 Symbol

無奈

簡單數據類型

ES5中有5中簡單數據類型,

  • Undefined
  • Null
  • Boolean
  • Number
  • String

相信大家都很熟悉,也使用的相當流利

嘿嘿

之後再來整理來給未來的我複習複習

今天重點要來整理Symbol到底能用在哪邊

根據MDN-Symbol說明,只有兩種類型可以做為Obj的key值

  • String 類型
  • Symbol 類型

如果使用另一種類型,例如數字,它會被自動轉換為字符串。
obj[1]obj["1"] 相同
obj[true]obj["true"] 相同

Symbol

語法

1
Symbol([description])

參數

description
可以選擇的String類型。
symbol 的描述,可用於調適 但不是訪問 symbol 本身。

Symbol 例子

“symbol” 值表示唯一的標識符。

可以給symbol 一個描述(也稱為symbol 名),這在代碼調試時非常有用:

1
2
// id 是描述為 "id" 的 symbol
let id = Symbol("id");

symbol 保證是唯一的。
即使我們創建了許多具有相同描述的symbol,它們的值也是不同。
ID只是一個標籤,不影響任何東西。
例如,這裡有兩個描述相同的symbol —— 它們不相等:

1
2
3
4
let id1 = Symbol("id");
let id2 = Symbol("id");

alert(id1 == id2); // false

例子二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

let s1 = Symbol('foo')
let s2 = Symbol('bar')

console.log(s1) // Symbol(foo)
console.log(s2) // Symbol(bar)
console.log(s1 === s2) // false
//---------------------------------------------------
const obj = {
name:"Cody",
toString(){
return this.name
}
}
let s = Symbol(obj) // 如果参数是Object的時候,會自動調用該對象toString方法
console.log(s) // Symbol(Cody)

關於description

1
2
3
4
5
6
7
8
9
10
let s = Symbol()
s.name = "Cody"
console.log(s) // Symbol{} // Symbol不是對象,不能用對待對象的方式對待Symbol
console.log(s.description) // undefind
console.log(s.name) // undefind
//---------------------------------------------
let s = Symbol('foo')
console.log(s.description) // foo


Symbol 需要給一個值,description才找的到東西

Symbol.for

  • 通過Symbol.for相當於定義在全局的變量,
    如果之前聲明過,後面再通過Symbol.for的時候,會在全局找,
    如果描述一樣的話,會和上一個一樣。

可以簡單理解為對象指向同一個堆內存地址。

舉個例子:

1
2
3
4
5
6
7
8
9
10
11
12
 let s1 = Symbol.for('foo')
let s2 = Symbol.for('foo')
console.log (s1) // Symbol(foo)
console log (s1 === s2) // true
// 即使是在函數定義域內,通過Symbol.for也會將該Symbol註冊在全局
function foo (){
return Symbol.for('foo')
}

const x = foo ()
const y = Symbol.for('foo')
console.log(x === y) // true

這樣理解為,Function return 的Symbol.for(‘foo’)
指向都是同一個地址的 (‘foo’)
而且Symbol.for會將指向只到全域

所以最後一行 X === Y 才會等於 True

完蛋!!打完都覺得要想十分鐘才轉得過來

眼神死

Symbol.keyFor

查看是否在全局登記Symbol裡面的描述。與上面的Symbol.for對應。

1
2
3
4
const s1 = Symbol('foo')
console.log(Symbol.keyFor(s1)) // undefind
const s2 = Symbol.for('foo')
console.log (Symbol.keyFor(s1)) // foo

這樣表示 s1 的Symbol 不是全域參數
s2 指向全域的地址 ,所以 Symbol.keyFor才搜尋的到

好了!!!看到這邊我知道你已經混亂了
該來點實際案例!!!!!!

驚訝

實際應用

應用一:解決對象 Obj 中key重複 但是表示不同訊息的情況

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
// 對象對於相同的key的訊息會進行覆蓋
const grade = {
zhangsan :{
address : "xxx" , tel : "111"
},
lisi :{
address : "yyy" , tel : "222"
},
lisi :{
address : "zzz" , tel : "333"
},
}

console.log (grade) // {zhangsan:{address:"xxx",tel:"111"},lisi:{address:"zzz",tel:"333"}}
// 通過變量構建對象
const stu1 = "lisi"
const stu2 = "lisi"
const grade = {
[stu1]:{
address : "yyy" , tel : "222"
},
[stu2]:{
address : "zzz" , tel : "333"
},
}
console . log (grade) // {lisi:{address:"zzz",tel:"333"}}



// es6通過Symbol解決key相同,訊息不同情況
const stu1 = Symbol ( "lisi" )
const stu2 = Symbol ( "lisi" )
const grade = {
[stu1]:{
address : "yyy" , tel : "222"
},
[stu2]:{
address : "zzz" , tel : "333"
},
}
console.log (grade) // {Symbol(lisi):{address:"yyy",tel:"222"},Symbol(lisi):{address:"zzz",tel:"333"}}
console.log (grade[stu1]) // {address:"yyy",tel:"222"}


應用二:保護 Class 中的部分屬性

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
// 定義基本類和類中方法調用
class User {
constructor ( name ){
this.name = name
}
getName (){
return this.name
}
}

const user = new User ( "lilei" )
console . log (user. getName ()) // lilei
// 不同循環遍歷方式獲取類內部屬性,根據是否可以獲取Symbol作為key的情況
const sym = Symbol ( "AILI" )
class User {
constructor ( name ){
this.name = name
this[sym] = "AILI.com"
}
getName (){
return this.name + this [sym]
}
}

const user = new User ( "lilei" )
console.log(user. getName ()) // lileiAILI.com

// 通過for...in 無法遍歷到Symbol屬性
for ( let key in user){
console . log (key) // name
}

// 同樣不能獲取到Symbol屬性
for ( let key of Object . keys (user)){
console.log (key) // name
}
// 只能取到Symbol屬性
for ( let key of Object . getOwnPropertySymbols (user)){
console.log (key) // Symbol(AILI)
}

// 即能獲取到普通屬性,又能獲取到Symbol屬性
for ( let key of Reflect . ownKeys (user)){
console.log (key) // name Symbol(AILI)
}

應用三:消除魔法字符串(比較長或者難以辨認,容易出錯的字符串)

真實開發情況

1
2
3
4
5
6
7
8
9
10
11
12
13
function getArea(shape){
let area = 0
switch(shape){
case "Triangle":
area = 1
break
case "Circle":
area = 2
break
}
return area
}
console.log(getArea("Triangle")) // 1

可以修改為下方情況

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 在這個函數中,【Triangle】和【Circle】已經不重要,只要區分開即可,利用Symbol不一致性
const shapeType = {
triangle : Symbol (),
circle : Symbol ()
}
function getArea ( shape ){
let area = 0
switch (shape){
case shapeType.triangle :
area = 1
break
case shapeType.circle :
area = 2
break
}
return area
}
console.log(getArea (shapeType.triangle )) // 1

這樣代碼就會簡潔很多

以上整理

希望會有比較清楚的感覺

搖頭


References

你的支持是我活力的來源 :)