Symbol簡單理解

Symbol

  • 概述
  • 作為屬性名的symbol
  • 屬性名的遍歷
  • Symbol的方法
  • 內(nèi)置的symbol值

概述

Symbol的原理:保證每一個屬性名都是獨(dú)一無二的潜的,從根本上防止屬性名的沖突。
symbol表示獨(dú)一無二的值字管,是JavaScript的第七種數(shù)據(jù)類型啰挪。

生成

Symbol值通過Symbol函數(shù),對象的屬性名現(xiàn)在可以有兩種類型嘲叔,一種是原來就有的字符串亡呵,另一種就是新增的 Symbol 類型。而Symbol類型的屬性名都是獨(dú)一無二的硫戈,保證不會與其他屬性名發(fā)生沖突锰什。

let s = Symbol();
typeof s;//Symbol

<mark>注意</mark>:Symbol函數(shù)前不能用new命令,這是因?yàn)樯傻?Symbol 是一個原始類型的值,不是對象歇由。

Symbol函數(shù)接受參數(shù)

字符串為參數(shù)(Symbol實(shí)例的描述卵牍,在打印時易于區(qū)分)

let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"

對象為參數(shù)

先調(diào)用對象的toString()方法將其轉(zhuǎn)為字符串,然后再生成Symbol值沦泌。

const obj = {
  toString() {
return 'abc';
  }
};
const sym = Symbol(obj);
sym // Symbol(abc)

<mark>注意</mark>:
1.Symbol函數(shù)的參數(shù)只是表示對當(dāng)前 Symbol 值的描述糊昙,因此相同參數(shù)的Symbol函數(shù)的返回值是不相等的。
2.Symbol值不能與其他類型的值進(jìn)行運(yùn)算
3.Symbol值可以顯式轉(zhuǎn)為字符串
4.Symbol值可以轉(zhuǎn)為布爾型谢谦,但不能轉(zhuǎn)為數(shù)值释牺。

作為屬性名的Symbol值

由于每一個 Symbol 值都是不相等的,這意味著 Symbol 值可以作為標(biāo)識符回挽,用于對象的屬性名没咙,就能保證不會出現(xiàn)同名的屬性。這對于一個對象由多個模塊構(gòu)成的情況非常有用千劈,能防止某一個鍵被不小心改寫或覆蓋祭刚。

let mySymbol = Symbol();
let a={};
a[Symbol]='Hello'//寫法一
Object.defineProperty(a,mySymbol,{ value: 'Hello' });//寫法二

<mark>注意</mark>:
1.Symbol作為對象屬性名時,不能用點(diǎn)運(yùn)算符墙牌。(點(diǎn)運(yùn)算符后面總是字符串)
2.在對象的內(nèi)部涡驮,使用 Symbol 值定義屬性時,Symbol 值必須放在方括號之中喜滨。方括號中的屬性名代表了Symbol值捉捅。
3.Symbol 值作為屬性名時,該屬性還是公開屬性虽风,不是私有屬性棒口。

魔術(shù)字符串

在代碼之中多次出現(xiàn)、與代碼形成強(qiáng)耦合的某一個具體的字符串或者數(shù)值辜膝。

屬性名的遍歷

Symbol 作為屬性名无牵,該屬性不會出現(xiàn)在for...infor...of循環(huán)中厂抖,也不會被Object.keys()合敦、Object.getOwnPropertyNames()JSON.stringify()返回验游。但是,它也不是私有屬性保檐,有一個Object.getOwnPropertySymbols方法耕蝉,可以獲取指定對象的所有 Symbol 屬性名。

  • Object.getOwnPropertySymbols():返回一個數(shù)組夜只,成員是當(dāng)前對象的所有用作屬性名的 Symbol 值垒在。
  • Reflect.ownKeys():返回所有類型的鍵名。
    let obj = {
      [Symbol('my_key')]: 1,
      enum: 2,
      nonEnum: 3
        };
    Reflect.ownKeys(obj)
    //  ["enum", "nonEnum", Symbol(my_key)]

Symbol的方法

Symbol.for()(重新使用同一個Symbol值)

它接受一個字符串作為參數(shù)扔亥,然后搜索有沒有以該參數(shù)作為名稱的 Symbol 值场躯。如果有谈为,就返回這個 Symbol 值,否則就新建并返回一個以該字符串為名稱的 Symbol 值踢关。

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true

Symbol.for()不會每次調(diào)用就返回一個新的Symbol類型的值伞鲫,而是會先檢查給定的key值是否已經(jīng)存在,不存在的話才會新建一個值签舞。而Symbol.()方法沒有登記機(jī)制秕脓,所以每次調(diào)用都是不同的值。

Symbol.Keyfor()

返回一個已登記的Symbol類型的值Key儒搭。

let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined

Singleton 模式

Singleton模式指的是調(diào)用一個類吠架,任何時候返回的都是同一個實(shí)例。

內(nèi)置的Symbol對象

Symbol.hasInstance

對象的該屬性指向一個內(nèi)部方法搂鲫。當(dāng)其他對象使用instanceof運(yùn)算符傍药,判斷是否為該對象的實(shí)例時,會調(diào)用這個方法魂仍。比如拐辽,foo instanceof Foo在語言內(nèi)部,實(shí)際調(diào)用的是Foo[Symbol.hasInstance] (foo)蓄诽。

Symbol.isConcatSpreadable(默認(rèn)等于undefined)

對象的Symbol.isConcatSpreadable屬性等于一個布爾值薛训,表示該對象用于Array.prototype.concat()時,是否可以展開仑氛。

//數(shù)組的默認(rèn)行為可以展開
let arr1 = ['c', 'd'];
['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
arr1[Symbol.isConcatSpreadable] // undefined

let arr2 = ['c', 'd'];
arr2[Symbol.isConcatSpreadable] = false;
['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']


//數(shù)組的對象默認(rèn)不展開
let obj = {length: 2, 0: 'c', 1: 'd'};
['a', 'b'].concat(obj, 'e') // ['a', 'b', obj, 'e']

obj[Symbol.isConcatSpreadable] = true;
['a', 'b'].concat(obj, 'e') // ['a', 'b', 'c', 'd', 'e']

Symbol.species

對象的Symbol.species屬性乙埃,指向一個構(gòu)造函數(shù)。創(chuàng)建衍生對象時锯岖,會使用該屬性介袜。

class MyArray extends Array {
  static get [Symbol.species]() { return Array; }
}

const a = new MyArray();
const b = a.map(x => x);

b instanceof MyArray // false
b instanceof Array // true

Symbol.match

對象的Symbol.match屬性,指向一個函數(shù)出吹。當(dāng)執(zhí)行str.match(myObject)時遇伞,如果該屬性存在,會調(diào)用它捶牢,返回該方法的返回值鸠珠。

String.prototype.match(regexp)
// 等同于
regexp[Symbol.match](this)

class MyMatcher {
  [Symbol.match](string) {
   return 'hello world'.indexOf(string);
  }
}

'e'.match(new MyMatcher()) // 1

Symbol.replace

對象的Symbol.replace屬性,指向一個方法秋麸,當(dāng)該對象被String.prototype.replace方法調(diào)用時渐排,會返回該方法的返回值。

  • symbol.replace接受兩個參數(shù):第一個參數(shù)是replace方法正在作用的對象灸蟆,第二個參數(shù)是替換后的值驯耻。

      String.prototype.replace(searchValue, replaceValue)
      // 等同于
      searchValue[Symbol.replace](this, replaceValue)
    

Symbol.search

對象的Symbol.search屬性,指向一個方法,當(dāng)該對象被String.prototype.search方法調(diào)用時可缚,會返回該方法的返回值霎迫。

String.prototype.search(regexp)
// 等同于
regexp[Symbol.search](this)

class MySearch {
constructor(value) {
this.value = value;
  }
[Symbol.search](string) {
return string.indexOf(this.value);
  }
}
'foobar'.search(new MySearch('foo')) // 0

Symbol.split

對象的Symbol.split屬性,指向一個方法帘靡,當(dāng)該對象被String.prototype.split方法調(diào)用時知给,會返回該方法的返回值。

String.prototype.split(separator, limit)
// 等同于
separator[Symbol.split](this, limit)

class MySplitter {
constructor(value) {
this.value = value;
  }
[Symbol.split](string) {
let index = string.indexOf(this.value);
if (index === -1) {
  return string;
}
return [
  string.substr(0, index),
  string.substr(index + this.value.length)
];
  }
}

'foobar'.split(new MySplitter('foo'))
// ['', 'bar']

'foobar'.split(new MySplitter('bar'))
// ['foo', '']

'foobar'.split(new MySplitter('baz'))
// 'foobar'

Symbol.iterator

對象的Symbol.iterator屬性测柠,指向該對象的默認(rèn)遍歷器方法炼鞠。
對象進(jìn)行for...of循環(huán)時,會調(diào)用Symbol.iterator方法轰胁,返回該對象的默認(rèn)遍歷器谒主。

class Collection {
  *[Symbol.iterator]() {
  let i = 0;
  while(this[i] !== undefined) {
  yield this[i];
  ++i;
}
  }
}

let myCollection = new Collection();
myCollection[0] = 1;
myCollection[1] = 2;

for(let value of myCollection) {
  console.log(value);
}
// 1
// 2

Symbol.toPrimitive

對象的Symbol.toPrimitive屬性,指向一個方法赃阀。該對象被轉(zhuǎn)為原始類型的值時霎肯,會調(diào)用這個方法,返回該對象對應(yīng)的原始類型值榛斯。
Symbol.toPrimitive:一個字符串參數(shù)观游,表示當(dāng)前運(yùn)算的模式,一共有三種模式驮俗。

  • Number:該場合需要轉(zhuǎn)成數(shù)值

  • String:該場合需要轉(zhuǎn)成字符串

  • Default:該場合可以轉(zhuǎn)成數(shù)值懂缕,也可以轉(zhuǎn)成字符串

      let obj = {
      [Symbol.toPrimitive](hint) {
      switch (hint) {
      case 'number':
      return 123;
      case 'string':
      return 'str';
      case 'default':
      return 'default';
      default:
      throw new Error();
        }
         }
      };
    
      2 * obj // 246
      3 + obj // '3default'
      obj == 'default' // true
      String(obj) // 'str'
    

Symbol.toStringTag

對象的Symbol.toStringTag屬性,指向一個方法王凑。在該對象上面調(diào)用Object.prototype.toString方法時搪柑,如果這個屬性存在,它的返回值會出現(xiàn)在toString方法返回的字符串之中索烹,表示對象的類型工碾。

// 例一
({[Symbol.toStringTag]: 'Foo'}.toString())
// "[object Foo]"

// 例二
class Collection {
get [Symbol.toStringTag]() {
return 'xxx';
  }
}
let x = new Collection();
Object.prototype.toString.call(x) // "[object xxx]"

Symbol.unscopables

對象的Symbol.unscopables屬性,指向一個對象百姓。<mark>該對象指定了使用with關(guān)鍵字時渊额,哪些屬性會被with環(huán)境排除。</mark>

Array.prototype[Symbol.unscopables]
// {
//   copyWithin: true,
//   entries: true,
//   fill: true,
//   find: true,
//   findIndex: true,
//   includes: true,
//   keys: true
// }

Object.keys(Array.prototype[Symbol.unscopables])
// ['copyWithin', 'entries', 'fill', 'find', 'findIndex', 'includes', 'keys']

<mark>上面代碼說明垒拢,數(shù)組有 7 個屬性旬迹,會被with命令排除。</mark>

參考文獻(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末求类,一起剝皮案震驚了整個濱河市奔垦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仑嗅,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異仓技,居然都是意外死亡鸵贬,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門脖捻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阔逼,“玉大人,你說我怎么就攤上這事地沮∈雀。” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵摩疑,是天一觀的道長危融。 經(jīng)常有香客問我,道長雷袋,這世上最難降的妖魔是什么吉殃? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮楷怒,結(jié)果婚禮上蛋勺,老公的妹妹穿的比我還像新娘。我一直安慰自己鸠删,他們只是感情好抱完,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布距帅。 她就那樣靜靜地躺著肠牲,像睡著了一般发绢。 火紅的嫁衣襯著肌膚如雪酣难。 梳的紋絲不亂的頭發(fā)上瞬测,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天慷妙,我揣著相機(jī)與錄音寿谴,去河邊找鬼匣距。 笑死庙楚,一個胖子當(dāng)著我的面吹牛上荡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播馒闷,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼酪捡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了纳账?” 一聲冷哼從身側(cè)響起逛薇,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎疏虫,沒想到半個月后永罚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啤呼,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年呢袱,在試婚紗的時候發(fā)現(xiàn)自己被綠了官扣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡羞福,死狀恐怖惕蹄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情治专,我是刑警寧澤卖陵,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站张峰,受9級特大地震影響泪蔫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜挟炬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一鸥滨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谤祖,春花似錦婿滓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至额湘,卻和暖如春卿吐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锋华。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工嗡官, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毯焕。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓衍腥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纳猫。 傳聞我的和親對象是個殘疾皇子婆咸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355