面試官:JavaScript 原始數(shù)據(jù)類型 Symbol 有什么用旁仿?

以前提到 JavaScript 原始數(shù)據(jù)類型時七兜,我們知道有NumberString钙蒙,Null茵瀑,BooleanUndefined這幾種躬厌。ES6 引入了新的基本數(shù)據(jù)類型SymbolBigInt马昨。今天我們就來了解下Symbol類型。Symbol類型是為了解決屬性名沖突的問題扛施,順帶還具備模擬私有屬性的功能鸿捧。

簡介

創(chuàng)建symbol變量最簡單的方法是用Symbol()函數(shù)。sysmbol變量有兩點比較特別:

  1. 它可以作為對象屬性名疙渣。只有字符串和 symbol 類型才能用作對象屬性名匙奴。
  2. 沒有兩個symbol 的值是相等的。
const symbol1 = Symbol();
const symbol2 = Symbol();

symbol1 === symbol2; // false

const obj = {};
obj[symbol1] = 'Hello';
obj[symbol2] = 'World';

obj[symbol1]; // 'Hello'
obj[symbol2]; // 'World'

盡管調(diào)用Symbol() 讓它看起來像是對象昌阿,實際上symbol是 JavaScript 原始數(shù)據(jù)類型饥脑。把Symbol當(dāng)作構(gòu)造函數(shù)來用 new會報錯恳邀。

const symbol1 = Symbol();

typeof symbol1; // 'symbol'
symbol1 instanceof Object; // false

// Throws "TypeError: Symbol is not a constructor"
new Symbol();

描述信息

Symbol()函數(shù)只有一個參數(shù),字符串description灶轰。這個字符串參數(shù)的唯一作用是輔助調(diào)試谣沸,也就是它的toString()值。但是請注意笋颤,兩個具有相同descriptionsymbol也是不相等的乳附。

const symbol1 = Symbol('my symbol');
const symbol2 = Symbol('my symbol');

symbol1 === symbol2; // false
console.log(symbol1); // 'Symbol(my symbol)'

有一個全局的symbol注冊中心,用Symbol.for()創(chuàng)建的symbol會添加到這個注冊中心伴澄,并用它的 description作為索引鍵赋除。也就是說,如果你用Symbol.for()創(chuàng)建帶有相同 description的兩個 symbol非凌,它們就是相等的举农。

const symbol1 = Symbol.for('test');
const symbol2 = Symbol.for('test');

symbol1 === symbol2; // true
console.log(symbol1); // 'Symbol(test)'

通常來說,除非你有非常好的理由敞嗡,否則不應(yīng)該使用全局注冊中心颁糟,因為這會造成命名沖突。

命名沖突

JavaScript 內(nèi)置了一個 symbol 喉悴,那就是 ES6 中的Symbol.iterator 棱貌。擁有Symbol.iterator函數(shù)的對象被稱為可迭代對象,就是說你可以在對象上使用for/of 循環(huán)箕肃。

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);
}

為什么這里要用Symbol.iterator 而不是字符串婚脱?假設(shè)不用Symbol.iterator ,可迭代對象需要有一個字符串屬性名'iterator'勺像,就像下面這個可迭代對象的類:

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++];
    })();
  }
}

MyClass 的實例是可迭代對象障贸,可以遍歷對象上面的屬性。但是上面的類有個潛在的缺陷咏删,假設(shè)有個惡意用戶給 MyClass 構(gòu)造函數(shù)傳了一個帶有iterator屬性的對象:

const obj = new MyClass({ iterator: 'not a function' });

這樣你在obj上使用for/of的話惹想,JavaScript 會拋出TypeError: obj is not iterable異常《胶可以看出,傳入對象的 iterator函數(shù)覆蓋了類的 iterator屬性激挪。這有點類似原型污染的安全問題辰狡,無腦復(fù)制用戶數(shù)據(jù)會對一些特殊屬性,比如__proto__constructor帶來問題垄分。

這里的核心在于宛篇,symbol讓對象的內(nèi)部數(shù)據(jù)和用戶數(shù)據(jù)井水不犯河水。由于sysmbol無法在 JSON 里表示薄湿,因此不用擔(dān)心給 Express API 傳入帶有不合適的Symbol.iterator屬性的數(shù)據(jù)叫倍。另外偷卧,對于那種混合了內(nèi)置函數(shù)和用戶數(shù)據(jù)的對象,比如 Mongoose model吆倦,你可以用symbol來確保用戶數(shù)據(jù)不會跟內(nèi)置屬性沖突听诸。

私有屬性

由于任何兩個symbol都是不相等的,在 JavaScript 里可以很方便地用來模擬私有屬性蚕泽。symbol不會出現(xiàn)在 Object.keys()的結(jié)果中晌梨,因此除非你明確地export 一個symbol,或者用 Object.getOwnPropertySymbols() 函數(shù)獲取须妻,否則其他代碼無法訪問這個屬性仔蝌。

function getObj() {
  const symbol = Symbol('test');
  const obj = {};
  obj[symbol] = 'test';
  return obj;
}

const obj = getObj();

Object.keys(obj); // []

// 除非有這個 symbol 的引用,否則無法訪問該屬性
obj[Symbol('test')]; // undefined

// 用 getOwnPropertySymbols() 依然可以拿到 symbol 的引用
const [symbol] = Object.getOwnPropertySymbols(obj);
obj[symbol]; // 'test'

還有一個原因是symbol不會出現(xiàn)在JSON.stringify()的結(jié)果里荒吏,確切地說是JSON.stringify()會忽略symbol屬性名和屬性值:

const symbol = Symbol('test');
const obj = { [symbol]: 'test', test: symbol };

JSON.stringify(obj); // "{}"

總結(jié)

Symbol 表示對象內(nèi)部狀態(tài)敛惊,可以很好地隔離用戶數(shù)據(jù)和程序狀態(tài)。有了它绰更,我們就不再需要某些命名約定了瞧挤,比如內(nèi)部屬性用'$'開頭。下次碰到需要定義私有屬性的時候动知,試試Symbol類型吧皿伺!


看到這個頗有氣質(zhì)的 logo,不來關(guān)注下嗎盒粮?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸵鸥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子丹皱,更是在濱河造成了極大的恐慌妒穴,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摊崭,死亡現(xiàn)場離奇詭異讼油,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)呢簸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門矮台,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人根时,你說我怎么就攤上這事瘦赫。” “怎么了蛤迎?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵确虱,是天一觀的道長。 經(jīng)常有香客問我替裆,道長校辩,這世上最難降的妖魔是什么窘问? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮宜咒,結(jié)果婚禮上惠赫,老公的妹妹穿的比我還像新娘。我一直安慰自己荧呐,他們只是感情好汉形,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著倍阐,像睡著了一般概疆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上峰搪,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天岔冀,我揣著相機(jī)與錄音,去河邊找鬼概耻。 笑死使套,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鞠柄。 我是一名探鬼主播侦高,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼厌杜!你這毒婦竟也來了奉呛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤夯尽,失蹤者是張志新(化名)和其女友劉穎瞧壮,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匙握,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡咆槽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了圈纺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秦忿。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蛾娶,靈堂內(nèi)的尸體忽然破棺而出小渊,到底是詐尸還是另有隱情,我是刑警寧澤茫叭,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站半等,受9級特大地震影響揍愁,放射性物質(zhì)發(fā)生泄漏呐萨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一莽囤、第九天 我趴在偏房一處隱蔽的房頂上張望谬擦。 院中可真熱鬧,春花似錦朽缎、人聲如沸惨远。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽北秽。三九已至,卻和暖如春最筒,著一層夾襖步出監(jiān)牢的瞬間贺氓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工床蜘, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留辙培,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓邢锯,卻偏偏與公主長得像扬蕊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子丹擎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前面的話 ES5中包含5種原始類型:字符串尾抑、數(shù)字、布爾值鸥鹉、null和undefined蛮穿。ES6引入了第6種原始類型...
    CodeMT閱讀 688評論 0 1
  • ES6 引入了一種新的原始數(shù)據(jù)類型Symbol,表示獨一無二的值毁渗。它是JavaScript語言的第七種數(shù)據(jù)類型践磅,前...
    語目閱讀 3,901評論 0 3
  • 概述 ES5的對象屬性名都是字符串,這容易造成屬性名的沖突灸异。比如府适,你使用了一個他人提供的對象,但又想為這個對象添加...
    oWSQo閱讀 529評論 1 3
  • 我的天啊……3年沒坐過這種車了……我也不知道說啥了……被這呼嚕聲吵得根本無法好好睡覺肺樟。 真的是很完美的給我們演繹了...
    maggiemiaomiao閱讀 292評論 0 0
  • 忽然聽到媽媽說起檐春,鄰居王阿姨被確診為宮頸癌。呂阿姨也因心肌梗塞住院么伯,心情甚是沉重疟暖。她們才50出頭,每個人都是為生活...
    靜謐A閱讀 469評論 3 10