學長突然問我用過Symbol嗎,我哽咽住了(準備捱罵)
theme: cyanosis
我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第1篇文章,點選檢視活動詳情
這天在實驗室和學長一起寫學校的專案,學長突然問我一句:“你用過Symbol嗎?” 然而我的大腦卻遍歷不出這個關鍵性名詞,啊,又要補漏了
Symbol
對於一些前端小白(比如我)來講,沒有特別使用過,只是在學習JS的時候瞭解了大概的概念,當時學習可能並沒有感覺到Symbol
在開發中有什麼特別的作用,而在學習一段時間後回頭看一遍,頓悟!
而本文將帶讀者從基本使用,特性應用到內建Symbol三個方面,帶大家深入Symbol
這個神奇的型別!
什麼是Symbol
😶🌫️
Symbol
作為原始資料型別的一種,表示獨一無二的值,在之前,物件的鍵以字串的形式存在,所以極易引發鍵名衝突問題,而Symbol
的出現正是解決了這個痛點,它的使用方式也很簡單。
Symbol
的使用
建立一個Symbol
與建立Object
不同,只需要a = Symbol()
即可
let a = Symbol()
typeof a
使用時需要注意的是:不可以使用new
來搭配Symbol()
構造例項,因為其會丟擲錯誤
let a = new Symbol()
typeof a // Symbol is not a constructor
通常使用new
來構造是想要得到一個包裝物件,而Symbol
不允許這麼做,那麼如果我們想要得到一個Symbol()
的物件形式,可以使用Object()
函式
let a = Symbol()
let b = Object(a)
typeof b // object
介紹到這裡,問題來了,Symbol
看起來都一樣,我們怎麼區分呢?我們需要傳入一個字串的引數用來描述Symbol()
let a = Symbol()
let b = Symbol()
上面看來a
和b
的值都是Symbol
,程式碼閱讀上,兩者沒區分,那麼我們呼叫Symbol()
函式的時候傳入字串用來描述我們構建的Symbol()
let a = Symbol("a")
let b = Symbol("b")
Symbol
的應用✌️
Symbol
的應用其實利用了唯一性的特性。
作為物件的屬性
大家有沒有想過,如果我們在不瞭解一個物件的時候,想為其新增一個方法或者屬性,又怕鍵名重複引起覆蓋的問題,而這個時候我們就需要一個唯一性的鍵來解決這個問題,於是Symbol
出場了,它可以作為物件的屬性的鍵,並鍵名避免衝突。
let a = Symbol()
let obj = {}
obj[a] = "hello world"
我在上面建立了一個symbol
作為鍵的物件,其步驟如下
- 建立一個
Symbol
- 建立一個物件
- 通過
obj[]
將Symbol
作為物件的鍵
值得注意的是我們無法使用.
來呼叫物件的Symbol
屬性,所以必須使用[]
來訪問Symbol
屬性
降低程式碼耦合
我們經常會遇到這種程式碼
if (name === "豬痞惡霸") {
console.log(1)
}
又或者
switch (name) {
case "豬痞惡霸"
console.log(1)
case "Ned"
console.log(2)
}
在這兩段段程式碼中作為判斷控制語句的"豬痞惡霸"
與"Ned"
被稱為魔術字串,即與程式碼強耦合的字串,可以理解為:與我們的程式程式碼強制繫結在一起,然而這會導致一個問題,在條件判斷複雜的情況下,我們想要更改我們的判斷條件,就需要更改每一個判斷控制,維護起來非常麻煩,所以我們可以換一種形式來解決字串與程式碼強耦合。
const judge = {
name_1:"豬痞惡霸"
name_2:"Ned"
}
switch (name) {
case judge.name_1
console.log(1)
case judge.name_2
console.log(2)
}
我們聲明瞭一個儲存判斷條件字串的物件,通過修改物件來自如地控制判斷條件,當然本小節的主題是Symbol
,所以還能繼續優化!
const judge = {
rectangle:Symbol("rectangle"),
triangle:Symbol("triangle")
}
function getArea(model, size) {
switch (model) {
case judge.rectangle:
return size.width * size.height
case judge.triangle:
return size.width * size.height / 2
}
}
let area = getArea(judge.rectangle ,{width:100, height:200})
console.log(area)
為了更加直觀地瞭解我們優化的過程,上面我建立了一個求面積的工具函式,利用Symbol
的特性,我們使我們的條件判斷更加精確,而如果是字串形式,沒有唯一的特點,可能會出現判斷錯誤的情況。
全域性共享Symbol
如果我們想在不同的地方呼叫已經同一Symbol
即全域性共享的Symbol
,可以通過Symbol.for()
方法,引數為建立時傳入的描述字串,該方法可以遍歷全域性登錄檔中的的Symbol
,當搜尋到相同描述,那麼會呼叫這個Symbol
,如果沒有搜尋到,就會建立一個新的Symbol
。
為了更好地理解,請看下面例子
let a = Symbol.for("a")
let b = Symbol.for("a")
a === b // true
如上建立Symbol
- 首先通過
Symbol.for()
在全域性登錄檔中尋找描述為a
的Symbol
,而目前沒有符合條件的Symbol
,所以建立了一個描述為a
的Symbol
- 當宣告
b
並使用Symbol.for()
在全域性登錄檔中尋找描述為a
的Symbol
,找到並賦值 - 比較
a
與b
結果為true
反映了Symbol.for()
的作用
再來看看下面這段程式碼
let a = Symbol("a")
let b = Symbol.for("a")
a === b // false
woc,結果竟然是false
,與上面的區別僅僅在於第一個Symbol
的建立方式,帶著驚訝的表情,來一步一步分析一下為什麼會出現這樣的結果
- 使用
Symbol("a")
直接建立,所以該Symbol("a")
不在全域性登錄檔中 - 使用
Symbol.for("a")
在全域性登錄檔中尋找描述為a
的Symbol
,並沒有找到,所以在全域性登錄檔中又建立了一個描述為a
的新的Symbol
- 秉承
Symbol
建立的唯一特性,所以a
與b
建立的Symbol
不同,結果為false
問題又又又來了!我們如何去判斷我們的Symbol
是否在全域性登錄檔中呢?
Symbol.keyFor()
幫我們解決了這個問題,他可以通過變數名查詢該變數名對應的Symbol
是否在全域性登錄檔中
let a = Symbol("a")
let b = Symbol.for("a")
Symbol.keyFor(a) // undefined
Symbol.keyFor(b) // 'a'
如果查詢存在即返回該Symbol
的描述,如果不存在則返回undefined
以上通過使用Symbol.for()
實現了Symbol
全域性共享,下面我們來看看Symbol
的另一種應用
內建Symbol
值又是什麼❔
上面的Symbol
使用是我們自定義的,而JS有內建了Symbol
值,個人的理解為:由於唯一性特點,在物件內,作為一個唯一性的鍵並對應著一個方法,在物件呼叫某方法的時候會呼叫這個Symbol
值對應的方法,並且我們還可以通過更改內建Symbol
值對應的方法來達到更改外部方法作用的效果。
為了更好地理解上面這一大段話,咱們以Symbol.hasInstance
作為例子來看看內建Symbol
到底是個啥!
class demo {
static [Symbol.hasInstance](item) {
return item === "豬痞惡霸"
}
}
"豬痞惡霸" instanceof demo // true
Symbol.hasInstance
對應的外部方法是instanceof
,這個大家熟悉吧,經常用於判斷型別。而在上面的程式碼片段中,我建立了一個demo
類,並重寫了Symbol.hasInstance
,所以其對應的instanceof
行為也會發生改變,其內部的機制是這樣的:當我們呼叫instanceof
方法的時候,內部對應呼叫Symbol.hasInstance
對應的方法即return item === "豬痞惡霸"
注:更多相關的內建Symbol
可以查閱相關文件😏
- 一份非官方的稀土掘金社群活動攻略
- 學長突然問我用過Symbol嗎,我哽咽住了(準備捱罵)
- 助力鄉村振興,我為農民伯伯開發了這款微信小程式
- 迷茫者的抉擇,我與掘金的故事,準大三生的年中總結
- 盤點幾種資料型別的解構賦值細節
- vue electron 開發一個實時監測github的跨端桌面應用
- 微信小程式實戰之骨架屏的應用與實現
- 小程式觸底載入與下拉重新整理功能的設計與實現
- 非Vuex實現的登入狀態判斷封裝
- 盤點JS判斷空物件的幾大方法
- 初識指令碼語言VBS
- 瀏覽器物件模型BOM的基本使用
- 基本的移動端適配
- WSL入門與Linux基礎❤
- 超Q的彈性盒子——flex✨
- 2021琴理工作室JS基礎教學(上)