Symbol 类型
Symbol 類型
1. Symbol 聲明
根據規范,對象的屬性鍵只能是字符串類型或者 Symbol 類型
Symbol 是一種基本數據類型,Symbol()函數會返回 symbol 類型的值,Symbol 值是唯一的標識符,不會與其他屬性名產生沖突
Tips:Symbol 函數前不能使用 new 命令,會報錯。這是因為生成的 Symbol 是一個原始類型的值,不是對象類型
let symbol1 = Symbol(); let symbol2 = Symbol(); console.log(symbol1 === symbol2); // false2. Symbol 描述與轉換
2-1 description 描述
Symbol 函數可以接受一個字符串作為參數,表示對 Symbol 實例的描述
ES2019 提供了一個實例屬性 description,直接返回 Symbol 的描述
// Symbol接受一個字符串作為參數 let sym = Symbol(1); // description來獲取Symbol描述 console.log(typeof sym.description); // [object String]如果 Symbol 的參數是一個對象,就會調用該對象的toString方法,將其轉為字符串,然后才生成一個 Symbol 值
let obj = {toString() {return 'symbol';} } let sym1 = Symbol(obj); console.log(sym1.description); // symbol2-2 類型轉換
-
Symbol 值不會發生隱式轉換,不會被自動轉換為字符串
-
如果我們真的想顯示一個 Symbol 值,可以通過 toString() 顯式轉為字符串
-
Symbol 值也可以轉為布爾值,但是不能轉為數值
3. 作為屬性名
由于每一個 Symbol 值都是不相等的,這意味著 Symbol 值可以作為標識符,用于對象的屬性名,就能保證不會出現同名的屬性
- Symbol 作為對象屬性的三種寫法
- Symbol 聲明和訪問使用 [] 方括號形式操作,不能使用 . 點語法因為 . 點語法是操作字符串屬性的
下面寫法是錯誤的,會將 Symbol 屬性當成字符串處理
let sym1 = Symbol(); let obj3 = {}; obj3.sym1 = 'hello' console.log(obj3[sym1]); // undefined console.log(obj3['sym1']); // hello- 在對象的內部,使用 Symbol 值定義屬性時,Symbol 值必須放在方括號之中
4. 屬性遍歷與復制
4-1 Symbol 屬性遍歷
Symbol 作為屬性名,遍歷對象時的情況:
- 不會出現在for...in、for...of 循環中
- Object.keys()、Object.getOwnPropertyNames()、JSON.stringify() 也會忽略 Symbol 屬性
- Object.assign 會同時復制字符串和 Symbol 屬性
4-2 獲取 Symbol 屬性
Object.getOwnPropertySymbols()
可以獲取指定對象的所有 Symbol 屬性名,該方法返回一個數組,數組元素是當前對象的所有用作屬性名的 Symbol 值
let sym = Symbol('學習'); let sym1 = Symbol('努力'); let sym2 = Symbol('加油'); let obj = {[sym]: 'hello',[sym1]: 'hello1',[sym2]: 'hello2', } console.log(obj[sym]); // hello let symbolAll = Object.getOwnPropertySymbols(obj) console.log(symbolAll); // [Symbol(學習), Symbol(努力), Symbol(加油)]5. Symbol.for()、Symbol.keyFor() 全局
5-1 Symbol.for()
通常所有的 Symbol 都是不同的,即使它們有相同的名字,如果需要使用同一個 Symbol 值,可以通過 Symbol.for() 方法來實現
Symbol.for() 接受一個字符串作為參數,然后搜索有沒有以該參數作為名稱的 Symbol 值
Tips: Symbol.for()、Symbol.keyFor() 都只獲取全局的 Symbol
- 如果有,就返回這個 Symbol 值
- 否則就新建一個以該字符串為名稱的 Symbol 值,并將其注冊到全局
5-2 Symbol.for() 與 Symbol() 區別
- Symbol.for() —— 會被登記在全局環境中供搜索,不會每次調用就返回一個新的 Symbol 類型的值,而是會先檢查給定的 key 是否已經存在,如果不存在才會新建一個值
- Symbol() —— 不會被登記在全局環境中供搜索,每次調用都會返回一個不同的值
5-3 Symbol.keyFor()
Symbol.keyFor(sym) 通過全局 Symbol 返回一個 Symbol 描述或者名字
如果 Symbol 不是全局的,它將無法找到它并返回 undefined
let sym = Symbol.for('hello'); let symkeyfor = Symbol.keyFor(sym); console.log(symkeyfor); // hello// 不是全局Symbol返回undefined let sym1 = Symbol('嘻嘻'); let symkeyfor1 = Symbol.keyFor(sym1); console.log(symkeyfor1); // undefined5-4 Reflect.ownKeys()
Reflect.ownKeys()方法可以返回所有類型的鍵名,包括常規鍵名和 Symbol 鍵名
let str = 'haha'; let sym = Symbol('symbol') let obj = {name: 'jsx',[str]: 'haha',[sym]: 'symbol' } let allKeys = Reflect.ownKeys(obj) console.log(allKeys); // ['name', 'haha', Symbol(symbol)]6. Symbol 使用場景
6-1 解決對象同名屬性沖突
作為對象屬性 當一個復雜對象中含有多個屬性的時候,很容易將某個屬性名覆蓋掉,利用 Symbol 值作為屬性名可以很好的避免這一現象
// let user1 = 'jsx';// let user2 = 'jsx';let user1 = Symbol('jsx');let user2 = Symbol('jsx');let obj = {[user1]: ['html', 'css', 'js'],[user2]: ['html', 'css', 'js', 'vue']}// 后面同名屬性覆蓋前面屬性// console.log(obj[user1]); // ['html', 'css', 'js', 'vue'] // console.log(obj[user2]); // ['html', 'css', 'js', 'vue']console.log(obj[user1]); // ['html', 'css', 'js'] console.log(obj[user2]); // ['html', 'css', 'js', 'vue']6-2 消除魔術字符串
當在代碼之中多次出現、與代碼形成強耦合的某一個具體的字符串或者數值時,可以通過 Symbol 消除魔術字符串,改由含義清晰的變量代替
const TYPE_AUDIO = Symbol('audio') const TYPE_VIDEO = Symbol('video') const TYPE_IMAGE = Symbol('image')function handleFileResource(resource) {switch (resource.type) {case TYPE_AUDIO:console.log(resource)breakcase TYPE_VIDEO:console.log(resource)breakcase TYPE_IMAGE:preconsole.log(resource)breakdefault:console.log('錯誤')} } handleFileResource({type: TYPE_AUDIO }) // {type: Symbol(audio)}6-3 對象屬性私有化
Symbol 作為對象屬性會隱藏自身屬性,Symbol 屬性不會被 for...in, Object.keys() 等等遍歷方法遍歷
let name = Symbol('jsx')function User() {this.lesson = ['jsx', 'ljj'];this.title = 'hello';this[name] = 'jsx'; } let user = new User(); console.log(user); // User {lesson: Array(2), title: 'hello', Symbol(jsx): 'jsx'} for (let item in user) {console.log(item); // lesson title }總結
- 上一篇: OS实验-模拟实现首次/最佳/最坏适应算
- 下一篇: 关于网络代理