🧑💻 寫在開頭
點贊 + 收藏 === 學會🤣🤣🤣
引言
在JavaScript的廣闊世界中,數據類型構成了其最基礎的語法元素。隨着ES6的發佈,這個大家庭迎來了兩位新成員:BigInt和Symbol。如果説BigInt是為了解決大數運算的精度問題,那麼Symbol的誕生,則像是一把為對象屬性開啓“隱私空間”和“唯一命名”的神奇鑰匙。本文將帶你深入理解這個“獨一無二”的簡單數據類型。
一、認識Symbol:一種新的簡單數據類型
JavaScript的八種數據類型,是每一位開發者的基本功,常被戲稱為“七上八下”:
-
簡單數據類型 (7種) :
- 傳統:
number、boolean、string、null、undefined - ES6新增:
bigint、symbol
- 傳統:
-
複雜數據類型 (1種) :
object
Symbol雖然用起來有點像構造函數(Symbol()),但它本質上是簡單數據類型。你可以通過typeof操作符來驗證這一點。
// 1.js const id1 = Symbol(); console.log(typeof id1); // 輸出:symbol
二、Symbol的核心特性:絕對的獨一無二
Symbol最核心、最迷人的特性,就是它的“獨一無二性”。每次調用Symbol()函數,都會返回一個全新的、與其他任何Symbol都不同的值,即使它們擁有相同的描述(label)。
// 1.js
const id1 = Symbol();
const id2 = Symbol();
console.log(id1 === id2); // 輸出:false
// 2.js
const s1 = Symbol('二哈');
const s2 = Symbol('二哈');
console.log(s1 === s2); // 輸出:false
你可以為Symbol傳入一個可選的字符串參數作為描述(label) ,例如Symbol('descrption')。這個描述僅僅是為了調試時方便識別,它不會影響Symbol的唯一性。兩個描述相同的Symbol,依然是兩個完全不同的值。這就像給兩把不同的鎖都貼上了“書房”的標籤,但鎖的齒紋(值)完全不同。
三、Symbol的核心應用:作為對象屬性的唯一鍵
Symbol最主要、最實用的場景,就是作為對象的屬性鍵(key) 。在ES6之前,對象的鍵只能是字符串,這在一個複雜、多人協作的代碼庫中極易引發命名衝突。
JavaScript是動態語言,任何人都可以輕鬆修改對象的屬性。當項目代碼龐大時,你可能會無意中覆蓋掉他人定義的重要屬性,或者自己的屬性被他人覆蓋,造成難以排查的Bug。
Symbol的引入,就是為了解決這個問題。用Symbol作為屬性名,可以創造出絕對安全的、不會與任何字符串屬性或其他Symbol屬性衝突的私有屬性。
1. 如何定義Symbol屬性?
你需要使用計算屬性名的語法,在[]中寫入Symbol變量。
// 2.js
const secretKey = Symbol('secret'); // 創建一個Symbol
console.log(secretKey, '//////'); // Symbol(secret) //////
const a = 'ecut';
const user = {
[secretKey]: '111222', // 使用Symbol作為鍵
email: '123456@qq.com',
name: '張三',
'a': '456', // 字符串'a'作為鍵
[a]: '123' // 使用變量a的值`'ecut'`作為鍵,相當於 `ecut: '123'`
};
console.log(user.ecut, user[a]); // 輸出:123 123
2. Symbol屬性的獨特優勢
- 命名安全:
secretKey這個屬性是獨一無二的,全局任何地方都無法用[Symbol('secret')]以外的其他Symbol訪問到它,也無法用字符串'secretKey'來訪問,這避免了屬性被意外覆蓋。 - 標籤不影響唯一性:即使兩個
Symbol描述相同,它們作為鍵也是互不衝突的。
// 3.html
const classRoom = {
[Symbol('Mark')]: {grade: 50, gender: 'male'},
[Symbol('oliva')]: {grade: 80, gender: 'female'},
// 即使標籤(描述)和上面一樣,這也是一個新的、獨立的屬性
[Symbol('oliva')]: {grade: 85, gender: 'female'},
"dl": ["張三","李四"]
};
上述代碼中,第二個[Symbol('oliva')]並沒有覆蓋第一個,而是創建了一個全新的屬性,完美解決了同名標籤可能帶來的衝突。
3. 枚舉與遍歷:Symbol的“隱藏”特性
Symbol屬性還有一個重要特性:它們不會被常規的遍歷方法枚舉到。例如,for...in循環、Object.keys()、Object.values()、Object.entries()以及JSON.stringify()都會“忽略”Symbol屬性。
// 3.html
for (const person in classRoom) {
console.log(classRoom[person], '////'); // 只會打印出 "dl" 的值
}
這使得Symbol屬性具備了一定的“私有”和“內置”屬性特徵,不會被輕易暴露出去。
如果你需要獲取對象中所有的Symbol屬性,必須使用專門的方法:
// 3.html const syms = Object.getOwnPropertySymbols(classRoom); // 返回一個包含對象自身所有Symbol鍵的數組 console.log(syms); // 打印出 [Symbol(Mark), Symbol(oliva), Symbol(oliva)] // 可以結合map方法獲取這些屬性的值 const data = syms.map(sym => classRoom[sym]); console.log(data); // 打印出三個學生的對象數組
四、總結
Symbol是ES6為解決JavaScript長期存在的屬性命名衝突和元編程問題而引入的一種優雅方案。它:
- 是簡單數據類型,獨一無二。
- 是創建對象唯一鍵的理想選擇,尤其在多人協作和庫的開發中,能有效保證屬性安全。
- 具有“半隱藏”特性,不會被常規方法枚舉,需用
Object.getOwnPropertySymbols()獲取。
掌握了Symbol,你就擁有了在JavaScript對象中創建“命名空間”和“內部插槽”的能力,讓你的代碼結構更清晰、更健壯。