Symbol基本類型

Symbol基本類型

Symbol 是一種解決命名沖突的工具。試想我們以前定義一個(gè)對(duì)象方法的時(shí)候總是要檢查是否已存在同名變量:

if(String && String.prototype && String.prototype.getCodeWith){
  String.prototype.getCodeWith = function(){};
}

可是這樣寫斥难,即便已存在同名方法枝嘶,但他們實(shí)現(xiàn)的功能不一定一樣,而且函數(shù)的接口也不一定適合自己哑诊。這樣我們就不得不再給自己的函數(shù)起個(gè)其他的名字群扶,可以萬(wàn)一又存在呢?

于是引入了 Symol镀裤,用來(lái)產(chǎn)生一個(gè)全局唯一的標(biāo)識(shí)符竞阐,你可以放心的使用它。
它接受一個(gè)字符串參數(shù)淹禾,作為該標(biāo)識(shí)符的描述:

var sym = Symbol("Discription");
var temp = Symbol("Discription");
console.log(sym);             //Symbol(Discription)
console.log(sym.valueOf());   //Symbol(Discription)
console.log(sym.toString());  //"Symbol(Discription)""
console.log(sym == temp);     //false

描述符是用來(lái)幫助開發(fā)人員區(qū)別不同是 symbol馁菜,不具備其他意義, 所以 symbol 值只有toString()valueOf() 方法。
Symbol 作為一個(gè)基本類型存在于 js 中铃岔。這樣汪疮,js 就有了6個(gè)基本類型: null, undefined, Boolean, Number, String, Symbol 和1個(gè)復(fù)雜類型: Object
使用 Symbol 需要注意以下幾點(diǎn):

  • Symbol 和 null, undefined 一樣不具有構(gòu)造函數(shù),不能用 new 調(diào)用毁习。
  • Symbol 值不能轉(zhuǎn)為數(shù)字智嚷,所以不能參與任何算術(shù),邏輯運(yùn)算
  • Symbol 雖然有 toString() 但 toString 得到的不是字符串纺且,所以不能用于字符串鏈接盏道,不能用于模板字符串
  • Symbol 可以轉(zhuǎn)換為 Boolean, 用在條件語(yǔ)句中,但所有 Symbol 都是邏輯 true
  • Symbol 作為屬性名時(shí)载碌,該屬性是公開的猜嘱,不是私有的

Symbol用作屬性名

這個(gè)應(yīng)該不陌生了,和普通標(biāo)識(shí)符用法類似,只是不能使用.訪問和定義嫁艇,必須使用[]

var sym = Symbol("abc");
var fun = Symbol("getSym");

var a = {};
a[sym] = 1;

var b = {
  [sym]: 1,
  [fun](){
    console.log(this[sym]);
  }
};

var c = Object.defineProperty({}, sym, {value: 1});

a[sym];   //1
b[sym];   //1
c[sym];   //1
b[fun]();  //1

當(dāng)然也可以定義一些常量朗伶,就像英語(yǔ)中 Symbol 代表一種象征,一個(gè)符號(hào):

var log = {
  DEBUG: Symbol('debug'),
  ERROR: Symbol('error'),
  WARNING: Symbol('warning'),
}

需要注意步咪,Symbol 屬性只有Object.getOwnPropertySymbols(obj)Reflect.ownKey(obj) 可以遍歷到:

  • Object.getOwnPropertySymbols(obj): 返回自身所有 Symbol 屬性名的數(shù)組论皆,包括不可枚舉屬性
  • Reflect.ownKey(obj): 返回自身所有屬性名數(shù)組,包括不可枚舉屬性和 Symbol 屬性名
var sym = Symbol("pro");
var o = {
  a: 1,
  b: 2,
  [sym]: 3
}
Object.getOwnPropertySymbols(o);     //[Symbol(pro)]
Reflect.ownKeys(o);                  //["a", "b", Symbol(pro)]

我們可以利用這個(gè)方法,構(gòu)造一些非私有的內(nèi)部變量:

var size = Symbol('size');
class Collection{
  constructor(){
    this[size] = 0;
  }
  add(num){
    this[this[size]] = item;
    this[size]++;
  }
  static sizeOf(instance){
    return instance[size];
  }
}
var x = new Collection();
console.log(Collection.sizeOf(x));     //0
x.add("foo");
console.log(Collection.sizeOf(x));     //1

console.log(Object.keys(x));     //['0']
console.log(Object.getOwnPropertyNames(x));   //['0']
console.log(Object.getOwnPropertySymbols(x));   //[Symbol(size)]

Symbol的靜態(tài)方法

  • Symbol.for("string"): 登記并重用一個(gè) symbol 值
Symbol.for("aa") === Symbol.for("aa");    //true
Symbol("aa") === Symbol("aa");            //false
  • Symbol.keyFor(symbol): 返回一個(gè)已登記的 Symbol 描述, 未登記的 Symbol 返回 undefined
var s1 = Symbol.for("aa");
var s2 = Symbol("aa");
Symbol.keyFor(s1);    //"aa"
Symbol.keyFor(s2);    //undefined

注意 Symbol 的登記是全局的:

iframe = document.createElement('iframe');
iframe.src = String(window.location);
document.body.appendChild(iframe);
iframe.contentWindow.Symbol.for("aa") === Symbol.for("aa");    //true

內(nèi)置的 Symbol 值

ES6 提供了12個(gè)內(nèi)置的 Symbol 值点晴,這12個(gè)值感凤,都是對(duì)象的,且都不可枚舉粒督、不可配置陪竿、不可修改。因?yàn)樗鼈兙哂衅涮厥庖饬x:

  1. Symbol.hasInstance: 指向一個(gè)內(nèi)部方法屠橄。判斷對(duì)象是否某個(gè)構(gòu)造函數(shù)的實(shí)例萨惑,instanceof 運(yùn)算符會(huì)調(diào)用它
  2. Symbol.isConcatSpreadable: 是一個(gè)數(shù)組對(duì)象屬性。如果為 false 該屬性在 concat 過(guò)程不會(huì)被展開仇矾。數(shù)組對(duì)象該屬性默認(rèn)值為 true, 類數(shù)組對(duì)象該屬性默認(rèn)值為 false
var arr = [3,4];
[1,2].concat(arr);   //[1,2,3,4]
arr[Symbol.isConcatSpreadable] = false;
[1,2].concat(arr);   //[1,2,[3,4]]

對(duì)于一個(gè)類而言,該屬性必須返回 boolean 類型

class A1 extends Array{
  [Symbol.isConcatSpreadable](){
    return true;
  }
}
class A2 extends Array{
  [Symbol.isConcatSpreadable](){
    return false;
  }
}
let a1 = new A1();
a1[0] = 3;
a1[1] = 4;
let a2 = new A2();
a2[0] = 5;
a2[1] = 6;
[1,2].concat(a1).concat(a2);  //[1, 2, 3, 4, 5, 6]
  1. Symbol.species: 指向一個(gè)方法解总。將對(duì)象作為構(gòu)造函數(shù)調(diào)用時(shí)贮匕,系統(tǒng)內(nèi)部會(huì)調(diào)用這個(gè)方法。即花枫,當(dāng) this.constructor[Symbol.species]存在時(shí)刻盐,以此為構(gòu)造函數(shù)構(gòu)建對(duì)象。
  2. Symbol.match: 指向一個(gè)函數(shù)劳翰。當(dāng)執(zhí)行 str.match(obj) 的時(shí)候, 如果 obj 存在該屬性敦锌,調(diào)用該方法并返回該方法的返回值
String.prototype.match(searchValue);
//相當(dāng)于
SearchValue[Symbol.match](this);
//實(shí)例
class myMatch{
  constructor(str){
    this.content = str;
  }
  [Symbol.match](str){
    return this.content.indexOf(str);
  }
}
'e'.match(new myMatch("Hello"));    //1
  1. Symbol.replace: 指向一個(gè)函數(shù)。和上一個(gè)方法類似的佳簸,當(dāng)執(zhí)行 str.replace(obj,replaceValue) 的時(shí)候, 如果 obj 存在該屬性乙墙,調(diào)用該方法并返回該方法的返回值
String.prototype.replace(searchValue, replaceValue);
//相當(dāng)于
SearchValue[Symbol.replace](this, replaceValue);
  1. Symbol.search: 指向一個(gè)函數(shù)。和上一個(gè)方法類似的生均,當(dāng)執(zhí)行 str.search(obj) 的時(shí)候, 如果 obj 存在該屬性听想,調(diào)用該方法并返回該方法的返回值
String.prototype.search(searchValue);
//相當(dāng)于
SearchValue[Symbol.search](this);
  1. Symbol.split: 指向一個(gè)函數(shù)。和上一個(gè)方法類似的马胧,當(dāng)執(zhí)行 str.split(obj,limit) 的時(shí)候, 如果 obj 存在該屬性汉买,調(diào)用該方法并返回該方法的返回值
String.prototype.split(seperator,limit);
//相當(dāng)于
seperator[Symbol.split](this,limit);
  1. Symbol.iterator: 指向默認(rèn)的遍歷器方法。對(duì)象在 for...of 中默認(rèn)調(diào)用該方法佩脊。
class Collector{
  constructor(...vals){
    this.nums = vals;
  }
  *[Symbol.iterator](){
    let i = this.nums.length;
    while(i){
      i--;
      yield this.nums[i];
    }
  }
}
var collector = new Collector(1,2,3,4,5);
for(let value of collector){
  console.log(value);        //依次輸出 5 4 3 2 1
}
  1. Symbol.toPrimitive: 指向一個(gè)方法蛙粘。對(duì)象被轉(zhuǎn)為原始類型值時(shí)會(huì)調(diào)用該方法。該方法介紹一個(gè)字符串參數(shù)威彰,可選參數(shù):
  • "number": 此時(shí)轉(zhuǎn)換成數(shù)值出牧,應(yīng)返回?cái)?shù)值類型
  • "string": 此時(shí)轉(zhuǎn)換成字符串,應(yīng)返回字符串類型
  • "default": 此時(shí)轉(zhuǎn)換成數(shù)值或字符串抱冷,應(yīng)返回?cái)?shù)值或字符串類型
var obj = {
  [Symbol.toPrimitive](hint){
    switch(hint){
      case 'number': return 1234;
      case 'string': return 'hello';
      case 'default': return 'default';
      default: throw new Error();
    }
  }
};
console.log(obj.toString());     //[object Object]
console.log(obj.valueOf());      //{
console.log(2 * obj);            //2468
console.log(2 + obj);            //2default
console.log(obj === "hello");    //false
console.log(String(obj));        //hello
  1. Symbol.unscopables: 該讀取器指向一個(gè)對(duì)象崔列。指定了在使用 with語(yǔ)句 時(shí),那些屬性被 with 環(huán)境排除(無(wú)法訪問)
//例1
console.log(Array.prototype[Symbol.unscopables]);    //輸出如下,數(shù)組對(duì)象在 with 中不能訪問這些屬性方法
//{
//copyWithin: true,
//entries: true,
//fill: true,
//find: true,
//findIndex: true,
//includes: true,
//keys: true
//}
//例2
//沒有 unscopables 時(shí)
class MyClass{
  foo(){return 1}
}
var foo = () => 2;
with(MyClass.prototype){
  foo();    //1
}

//有 unscopable 時(shí)
var foo = () => 2;
class MyClass{
  foo(){return 1;}
  get [Symbol.unscopables](){
    return {foo:true};
  }
}
with(MyClass.prototype){
  foo();    //2
}
  1. Symbol.toStringTag: 指向一個(gè)方法。該方法指向函數(shù)名是對(duì)象 toString 返回值 [object Array]Array 部分赵讯。
var b = {
  [Symbol.toStringTag]:"Hello"
};
console.log(b.toString());    //"[object Hello]"

ES6 新增的 Symbol.toStringTag 如下:

  • JSON["Symbol.toStringTag"]: 'JSON'
  • Math["Symbol.toStringTag"]: 'Math'
  • Module對(duì)象 M["Symbol.toStringTag"]: 'Module'
  • ArrayBuffer.prototype["Symbol.toStringTag"]: 'ArrayBuffer'
  • DataView.prototype["Symbol.toStringTag"]: 'DataView'
  • Map.prototype["Symbol.toStringTag"]: 'Map'
  • Promise.prototype["Symbol.toStringTag"]: 'Promise'
  • Set.prototype["Symbol.toStringTag"]: 'Set'
  • %TypedArray%.prototype["Symbol.toStringTag"]: 'Uint8Array'等9種
  • WeakMap.prototype["Symbol.toStringTag"]: 'WeakMap'
  • WeakSet.prototype["Symbol.toStringTag"]: 'WeakSet'
  • %MapIteratorPrototype%["Symbol.toStringTag"]: 'Map Iterator'
  • %SetIteratorPrototype%["Symbol.toStringTag"]: 'Set Iterator'
  • %StringIteratorPrototype%["Symbol.toStringTag"]: 'String Iterator'
  • Symbol.prototype["Symbol.toStringTag"]: 'Symbol'
  • Generator.prototype["Symbol.toStringTag"]: 'Generator'
  • GeneratorFunction.prototype["Symbol.toStringTag"]: 'GeneratorFunction'
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盈咳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子边翼,更是在濱河造成了極大的恐慌鱼响,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件组底,死亡現(xiàn)場(chǎng)離奇詭異丈积,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)债鸡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門江滨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人厌均,你說(shuō)我怎么就攤上這事唬滑。” “怎么了棺弊?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵晶密,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我模她,道長(zhǎng)稻艰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任侈净,我火速辦了婚禮尊勿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘畜侦。我一直安慰自己运怖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布夏伊。 她就那樣靜靜地躺著摇展,像睡著了一般。 火紅的嫁衣襯著肌膚如雪溺忧。 梳的紋絲不亂的頭發(fā)上咏连,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音鲁森,去河邊找鬼祟滴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛歌溉,可吹牛的內(nèi)容都是我干的垄懂。 我是一名探鬼主播骑晶,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼草慧!你這毒婦竟也來(lái)了桶蛔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤漫谷,失蹤者是張志新(化名)和其女友劉穎仔雷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舔示,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碟婆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惕稻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竖共。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖俺祠,靈堂內(nèi)的尸體忽然破棺而出肘迎,到底是詐尸還是另有隱情,我是刑警寧澤锻煌,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站姻蚓,受9級(jí)特大地震影響宋梧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜狰挡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一捂龄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧加叁,春花似錦倦沧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至豫柬,卻和暖如春告希,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背烧给。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工燕偶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人础嫡。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓指么,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子伯诬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

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