溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JavaScript 中的 Symbols 怎么用

發(fā)布時(shí)間:2020-06-07 07:03:39 來源:網(wǎng)絡(luò) 閱讀:200 作者:wx5d721be2ee1ef 欄目:編程語言

為了防止屬性名沖突, JavaScript 介紹了一種?symbols?的類型。在 2015 - 2019 中,symbols 提供一種方法去模擬私有屬性。

簡介

創(chuàng)建 symbol 最簡單的方式是調(diào)用?Symbol()?方法。有兩個(gè)關(guān)鍵屬性使得 symbols 變得特殊:

  1. Symbols 可以用于對象 key。只有字符串和 symbol 可以被用于對象 key。

  2. 任何兩個(gè) sybmols 都不相等

const?symbol1?=?Symbol();?const?symbol2?=?Symbol();?symbol1?===?symbol2;?//?false?const?obj?=?{};?obj[symbol1]?=?'Hello';?obj[symbol2]?=?'World';?obj[symbol1];?//?'Hello'?obj[symbol2];?//?'World'?復(fù)制代碼

盡管 symbol() 看起來是個(gè)對象,實(shí)際上它也屬于?7 種基本類型。對 Symbol 使用 new 操作符會導(dǎo)致一個(gè)錯(cuò)誤。

const?symbol1?=?Symbol();?typeof?symbol1;?//?'symbol'?symbol1?instanceof?Object;?//?false?//?Throws?"TypeError:?Symbol?is?not?a?constructor"?new?Symbol();?復(fù)制代碼

描述符

Symbol 方法使用單個(gè)字符串參數(shù)當(dāng)做描述符。Symbol 的描述符只是用于 debug 的目的。描述符在 symbol 調(diào)用 toString 的時(shí)候出現(xiàn)。然而,兩個(gè)相同描述符的 symbol 也是不相等的。

const?symbol1?=?Symbol('my?symbol');?const?symbol2?=?Symbol('my?symbol');?symbol1?===?symbol2;?//?false?console.log(symbol1);?//?'Symbol(my?symbol)'?復(fù)制代碼

通常情況下,除非你有合適的理由,不然一般不建議使用全局 symbol 注冊,這么做有可能導(dǎo)致命名沖突。

命名沖突

JavaScript 中的第一個(gè)內(nèi)置 symbol 是 Symbol.iterator。一個(gè)有 Symbol.iterator 方法當(dāng)做迭代的對象。也就意味著。你可以使用這個(gè)對象作為循環(huán)的右操作符。

比如獲取斐波那契數(shù)列:

const?fibonacci?=?{???[Symbol.iterator]:?function*()?{?????let?a?=?1;?????let?b?=?1;?????let?temp;?????yield?b;?????while?(true)?{???????temp?=?a;???????a?=?a?+?b;???????b?=?temp;???????yield?b;?????}???}?};?//?Prints?every?Fibonacci?number?less?than?100?for?(const?x?of?fibonacci)?{???if?(x?>=?100)?{?????break;???}???console.log(x);?}?復(fù)制代碼

為什么 Symbol.iterator 是 symbol 而不是 string? 假設(shè)不使用 Symbol.iterator,迭代名定義為一個(gè)字符串屬性的 iterator。也就是說,假設(shè)有一個(gè)可迭代的類,如下:

class?MyClass?{???constructor(obj)?{?????Object.assign(this,?obj);???}???iterator()?{?????const?keys?=?Object.keys(this);?????let?i?=?0;?????return?(function*()?{???????if?(i?>=?keys.length)?{?????????return;???????}???????yield?keys[i++];?????})();???}?}?復(fù)制代碼

MyClass 允許你迭代對象 keys。但是上面的類有個(gè)潛在的錯(cuò)誤。假設(shè)用戶故意給對象傳遞一個(gè) iterator 的屬性。比如:

const?obj?=?new?MyClass({?iterator:?'not?a?function'?});?復(fù)制代碼

這樣的話,迭代就會失效。JavaScript 在你使用 for/of 迭代時(shí),會拋出一個(gè)錯(cuò)誤 obj is not iterable。這是因?yàn)樯厦娴拇a覆蓋了類中的迭代屬性。這是類似原型污染的安全問題。在想當(dāng)然拷貝用戶數(shù)據(jù)的時(shí)候容易發(fā)生這樣的問題,尤其是?proto?和 constructor 這樣的屬性。

關(guān)鍵模式在于 symbol 可以清楚的分割用戶數(shù)據(jù)和對象數(shù)據(jù)。由于符號無法用JSON表示,因此不存在將數(shù)據(jù)傳遞到具有錯(cuò)誤 Symbol.iterator 屬性的 Express API 的風(fēng)險(xiǎn)。 在將用戶數(shù)據(jù)與內(nèi)置函數(shù)和方法(如Mongoose模型)混合的對象中,可以使用符號來確保用戶數(shù)據(jù)不會與內(nèi)置功能沖突。

私有屬性

既然任意兩個(gè) symbol 都不相等,symbol 可以方便的模擬 JavaScript 中的私有屬性。 Symbols 不會在?Object.key(),中出現(xiàn),因?yàn)槌悄忝鞔_ export 一個(gè) symbol,沒有任何代碼可以訪問到這個(gè)屬性,除非使用 Object.getOwnPropertySymbols() 方法。

function?getObj()?{???const?symbol?=?Symbol('test');???const?obj?=?{};???obj[symbol]?=?'test';???return?obj;?}?const?obj?=?getObj();?Object.keys(obj);?//?[]?//?Unless?you?explicitly?have?a?reference?to?the?symbol,?you?can't?access?the?//?symbol?property.?obj[Symbol('test')];?//?undefined?//?You?can?still?get?a?reference?to?the?symbol?using?`getOwnPropertySymbols()`?const?[symbol]?=?Object.getOwnPropertySymbols(obj);?obj[symbol];?//?'test'?復(fù)制代碼

Symbols 作為私有屬性方便的一點(diǎn)是,它不會在 JSON.stringify() 中出現(xiàn)。

最后

Symbols 處理對象內(nèi)部狀態(tài)保證用戶數(shù)據(jù)和程序數(shù)據(jù)分離是很不錯(cuò)的一個(gè)工具。使用 symbols 就不需要再加上各種前綴表示程序狀態(tài)。下次可以試試 symbol。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI