六: ES6 符號 Symbol

前言

該部分為書籍 深入理解ES6 第六章(符號與符號屬性)筆記

創(chuàng)建符號值

  • 符號沒有字面量形式, 這在 JS 的基本類型中是獨一無二的. 使用全局 Symbol 函數(shù)來創(chuàng)建一個符號值
  • 由于符號值是基本類型的值, 因此調(diào)用 new Symbol() 將會拋出錯誤. 你可以通過 new
    Object(yourSymbol) 來創(chuàng)建一個符號實例,但尚不清楚這能有什么作用。
  • Symbol 函數(shù)還可以接受一個額外的參數(shù)用于描述符號值, 該描述不能用來訪問對應(yīng)屬性, 但它能用于調(diào)試. 符號的描述信息被存儲在內(nèi)部屬性 [[Description]] 中, 當(dāng)符號的 toString() 方法被顯式或隱式調(diào)用時, 該屬性都會被讀取. 此外沒有任何辦法可以從代碼中直接訪問 [[Description]] 屬性
let firstName = Symbol("first name");
let person = {};

person[firstName] = "Nicholas";

console.log("first name" in person); // false
console.log(person[firstName]); // "Nicholas"
console.log(firstName); // "Symbol(first name)"
  • 識別符號值: 可以使用 typeof 運算符來判斷一個變量是否為符號

    let symbol = Symbol("test symbol");
    
    console.log(typeof symbol); // "symbol"
    

    盡管有其他方法可以判斷一個變量是否為符號蓄喇, typeof 運算符依然是最準確、最優(yōu)先
    的判別手段乍炉。

使用符號值

可以在任意能使用 "需計算屬性名" 的場合使用符號. 還可以在 Object.defineProperty()Object.defineProperties() 調(diào)用中使用它

let firstName = Symbol("first name");

// 使用一個需計算字面量屬性
let person = {
    [firstName]: "Nicholas"
};

// 讓該屬性變?yōu)橹蛔x
Object.defineProperty(person, firstName, { writable: false });

let lastName = Symbol("last name");

Object.defineProperties(person, {
    [lastName]: {
        value: "Zakas",
        writable: false
    }
});

console.log(person[firstName]); // "Nicholas"
console.log(person[lastName]); // "Zakas"

共享符號值

  • 創(chuàng)建共享符號值, 應(yīng)使用 Symbol.for() 方法而不是 Symbol() 方法. Symbol.for()方法僅接受單個字符串類型的參數(shù)根欧,作為目標符號值的標識符,同時此參數(shù)也會成為該符號的描述信息瞬测。

    let uid = Symbol.for("uid");
    let object = {};
    
    object[uid] = "12345";
    
    console.log(object[uid]); // "12345"
    console.log(uid); // "Symbol(uid)"
    
  • Symbol.for() 方法首先會搜索全局符號注冊表,看是否存在一個鍵值為 "uid" 的符號值纠炮。若是月趟,該方法會返回這個已存在的符號值;否則恢口,會創(chuàng)建一個新的符號值孝宗,并使用該鍵值將其記錄到全局符號注冊表中,然后返回這個新的符號值

  • let uid = Symbol.for("uid");
    let object = {
      [uid]: "12345"
    };
    
    console.log(object[uid]); // "12345"
    console.log(uid); // "Symbol(uid)"
    
    let uid2 = Symbol.for("uid");
    
    console.log(uid === uid2); // true
    console.log(object[uid2]); // "12345"
    console.log(uid2); // "Symbol(uid)"
    
  • 可以使用 Symbol.keyFor() 方法在全局符號注冊表中根據(jù)符號值檢索出對應(yīng)的鍵值,

    注意: 使用 Symobol() 方法創(chuàng)建的是不會注冊到全局符號注冊表的

    let uid = Symbol.for("uid");
    console.log(Symbol.keyFor(uid)); // "uid"
    
    let uid2 = Symbol.for("uid");
    console.log(Symbol.keyFor(uid2)); // "uid"
    
    let uid3 = Symbol("uid");
    console.log(Symbol.keyFor(uid3)); // undefined
    
  • 全局符號注冊表類似于全局作用域耕肩,是一個共享環(huán)境因妇,這意味著你不應(yīng)當(dāng)假設(shè)某些值是否已存在于其中问潭。在使用第三方組件時,為符號的鍵值使用命名空間能夠減少命名沖突的可能性婚被,舉個例子: jQuery 代碼應(yīng)當(dāng)為它的所有鍵值使用 "jquery." 的前綴狡忙,如"jquery.element" 或類似的形式。

符號值的轉(zhuǎn)換

  • 符號類型在進行轉(zhuǎn)換時非常不靈活, 因為其他類型缺乏與符號值的合理等價, 尤其是符號值無法被轉(zhuǎn)換為字符串值或數(shù)值(會拋出錯誤)
  • 無論對符號使用哪種數(shù)學(xué)運算符都會導(dǎo)致錯誤址芯,但使用邏輯運算符則不會去枷,因為符號值在邏輯運算中會被認為等價于 true (就像 JS中其他的非空值那樣)。

檢索符號屬性

ES6 新增了Object.getOwnPropertySymbols() 方法是复,以便讓你可以檢索對象的符號類型屬性删顶。

let uid = Symbol.for("uid");
let object = {
    [uid]: "12345"
};

let symbols = Object.getOwnPropertySymbols(object);

console.log(symbols.length); // 1
console.log(symbols[0]); // "Symbol(uid)"
console.log(object[symbols[0]]); // "12345"

使用知名符號暴露內(nèi)部方法

ES5 的中心主題之一是披露并定義了一些魔術(shù)般的成分,而這些部分是當(dāng)時開發(fā)者所無法自行模擬的淑廊。 ES6 延續(xù)了這些工作逗余,對原先屬于語言內(nèi)部邏輯的部分進行了進一步的暴露,允許使用符號類型的原型屬性來定義某些對象的基礎(chǔ)行為季惩。

**這些符號是: **

  1. Symbol.hasInstance :供 instanceof 運算符使用的一個方法录粱,用于判斷對象繼承關(guān)系。
  2. Symbol.isConcatSpreadable :一個布爾類型值画拾,在集合對象作為參數(shù)傳遞給Array.prototype.concat() 方法時啥繁,指示是否要將該集合的元素扁平化。
  3. Symbol.iterator :返回迭代器(參閱第七章)的一個方法青抛。
  4. Symbol.match :供 String.prototype.match() 函數(shù)使用的一個方法旗闽,用于比較字符串。
  5. Symbol.replace :供 String.prototype.replace() 函數(shù)使用的一個方法蜜另,用于替換子字符串适室。
  6. Symbol.search :供 String.prototype.search() 函數(shù)使用的一個方法,用于定位子字符串
  7. Symbol.species :用于產(chǎn)生派生對象(參閱第八章)的構(gòu)造器举瑰。
  8. Symbol.split :供 String.prototype.split() 函數(shù)使用的一個方法捣辆,用于分割字符串。
  9. Symbol.toPrimitive :返回對象所對應(yīng)的基本類型值的一個方法此迅。
  10. Symbol.toStringTag :供 String.prototype.toString() 函數(shù)使用的一個方法汽畴,用于創(chuàng)建對象的描述信息。
  11. Symbol.unscopables :一個對象耸序,該對象的屬性指示了哪些屬性名不允許被包含在with 語句中忍些。

重寫知名符號所定義的方法, 會把一個普通對象改變成奇異對象, 因為它改變了一些默認的內(nèi)部行為

1. Symbol.hasInstance 屬性

  • 作用: 用于判斷指定對象是否為本函數(shù)的一個實例。 方法定義在 Function.prototype 上, 因此所有函數(shù)都繼承了面對 instanceof 運算符時的默認行為

    obj instanceof Array;
    
    // 等價于 -- ES6 從本質(zhì)上將 instanceof 運算符重定義為上述方法調(diào)用的簡寫語法佑吝,這樣使用 instanceof 便會觸發(fā)一次方法調(diào)用坐昙,實際上允許你改變該運算符的工作绳匀。
    Array[Symbol.hasInstance](obj);
    
  • Symbol.hasInstance 屬性自身是不可寫入芋忿、不可配置炸客、不可枚舉的,從而保證它不會被錯誤地重寫

  • 要重寫一個不可寫入的屬性戈钢, 必須使用 Object.defineProperty()

    function SpecialNumber() {
      // empty
    }
    
    // 通過重寫構(gòu)造函數(shù)本身的屬性來重寫 instanceof 運算符的結(jié)果
    Object.defineProperty(SpecialNumber, Symbol.hasInstance, {
      value: function(v) {
            // 將介于 1 到 100 之間的數(shù)值認定為一個特殊的數(shù)值類型痹仙,
          return (v instanceof Number) && (v >=1 && v <= 100);
      }
    });
    
    let two = new Number(2),
      zero = new Number(0);
    
    console.log(two instanceof SpecialNumber); // true
    console.log(zero instanceof SpecialNumber); // false
    
    
  • 可以重寫所有內(nèi)置函數(shù)(例如 Date 或 Error )的 Symbol.hasInstance 屬性,但并不建議這么做殉了,因為這會讓你的代碼變得難以預(yù)測而又混亂开仰。最好僅在必要時對自己的函數(shù)重寫Symbol.hasInstance 。

2. Symbol.isConcatSpreadable

  • 作用: Symbol.isConcatSpreadable 屬性是一個布爾類型的屬性薪铜,它表示目標對象擁有長度屬性與數(shù)值類型的鍵众弓、并且數(shù)值類型鍵所對應(yīng)的屬性值在參與 concat() 調(diào)用時需要被分離為個體。

3. Symbol.match隔箍、 Symbol.replace谓娃、Symbol.search、Symobol.split

  • 作用: 這 4 個符號表示可以將正則表達式作為字符串對應(yīng)方法的第一個參數(shù)傳入蜒滩, Symbol.match對應(yīng) match() 方法滨达, Symbol.replace 對應(yīng) replace() , Symbol.search 對應(yīng) search()俯艰, Symbol.split 則對應(yīng) split() 捡遍。這些符號屬性被定義在 RegExp.prototype 上作為默認實現(xiàn),以供對應(yīng)的字符串方法使用竹握。

4. Symbol.toPrimittive

  • 作用: Symbol.toPrimitive 方法被定義在所有常規(guī)類型的原型上画株,規(guī)定了在對象被轉(zhuǎn)換為基本類型值的時候會發(fā)生什么。當(dāng)需要轉(zhuǎn)換時啦辐, Symbol.toPrimitive 會被調(diào)用污秆,并按照規(guī)范傳入一個提示性字符串參數(shù)。該參數(shù)有 3 種可能:當(dāng)參數(shù)值為 "number" 的時候昧甘,Symbol.toPrimitive 應(yīng)當(dāng)返回一個數(shù)值良拼;當(dāng)參數(shù)值為 "string" 的時候,應(yīng)當(dāng)返回一個字符串充边;而當(dāng)參數(shù)為 "default" 的時候庸推,對返回值類型沒有特別要求。

    通過定義 Symbol.toPrimitive 方法浇冰,你可以重寫這些默認的轉(zhuǎn)換行為贬媒。

    對于大部分常規(guī)對象,“數(shù)值模式”依次會有下述行為:

    1. 調(diào)用 valueOf() 方法肘习,如果方法返回值是一個基本類型值际乘,那么返回它;
    2. 否則漂佩,調(diào)用 toString() 方法脖含,如果方法返回值是一個基本類型值罪塔,那么返回它;
    3. 否則养葵,拋出一個錯誤征堪。

    類似的,對于大部分常規(guī)對象关拒,“字符串模式”依次會有下述行為:

    1. 調(diào)用 toString() 方法佃蚜,如果方法返回值是一個基本類型值,那么返回它着绊;

    2. 否則谐算,調(diào)用 valueOf() 方法,如果方法返回值是一個基本類型值归露,那么返回它氯夷;

    3. 否則,拋出一個錯誤

    在多數(shù)情況下靶擦,常規(guī)對象的默認模式都等價于數(shù)值模式(只有 Date 類型例外腮考,它默認使用
    字符串模式)
    ==> “默認模式”只在使用 == 運算符、 + 運算符玄捕、或者傳遞單一參數(shù)給 Date 構(gòu)造器的時候被使用踩蔚,而大部分運算符都使用字符串模式或是數(shù)值模式

function Temperature(degrees) {
    this.degrees = degrees;
}

Temperature.prototype[Symbol.toPrimitive] = function(hint) {
    switch (hint) {
        case "string":
            return this.degrees + "\u00b0"; // 溫度符號
        case "number":
            return this.degrees;
        case "default":
            return this.degrees + " degrees";
    }
};

let freezing = new Temperature(32);

console.log(freezing + "!"); // "32 degrees!"
console.log(freezing / 2); // 16
console.log(String(freezing)); // "32°"

5. Symbol.toStringTag

  • 作用: ES6 通過 Symbol.toStringTag 重定義了相關(guān)行為,該符號代表了所有對象的一個屬性枚粘,定義了 Object.prototype.toString.call() 被調(diào)用時應(yīng)當(dāng)返回什么值馅闽。也就是修改對象內(nèi)部屬性[[class]]
function Person(name) {
    this.name = name;
}

Person.prototype[Symbol.toStringTag] = "Person";

let me = new Person("Nicholas");

console.log(me.toString()); // "[object Person]"
console.log(Object.prototype.toString.call(me)); // "[object Person]"

6. Symbol.unscopables

  • 作用: 在 Array.prototype 上使用,以指定哪些屬性不允許在 with 語句內(nèi)被綁定馍迄。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末福也,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子攀圈,更是在濱河造成了極大的恐慌暴凑,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赘来,死亡現(xiàn)場離奇詭異现喳,居然都是意外死亡,警方通過查閱死者的電腦和手機犬辰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門嗦篱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人幌缝,你說我怎么就攤上這事灸促。” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵浴栽,是天一觀的道長荒叼。 經(jīng)常有香客問我,道長吃度,這世上最難降的妖魔是什么甩挫? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任贴硫,我火速辦了婚禮椿每,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘英遭。我一直安慰自己间护,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布挖诸。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪刚照。 梳的紋絲不亂的頭發(fā)上送漠,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音狼荞,去河邊找鬼辽装。 笑死,一個胖子當(dāng)著我的面吹牛相味,可吹牛的內(nèi)容都是我干的拾积。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼丰涉,長吁一口氣:“原來是場噩夢啊……” “哼拓巧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起一死,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤肛度,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后投慈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贤斜,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年逛裤,在試婚紗的時候發(fā)現(xiàn)自己被綠了瘩绒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡带族,死狀恐怖锁荔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蝙砌,我是刑警寧澤阳堕,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布跋理,位于F島的核電站,受9級特大地震影響恬总,放射性物質(zhì)發(fā)生泄漏前普。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一壹堰、第九天 我趴在偏房一處隱蔽的房頂上張望拭卿。 院中可真熱鬧,春花似錦贱纠、人聲如沸峻厚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惠桃。三九已至,卻和暖如春辖试,著一層夾襖步出監(jiān)牢的瞬間辜王,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工罐孝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留呐馆,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓肾档,卻偏偏與公主長得像摹恰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子怒见,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

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

  • 引 在 JS 已有的基本類型(字符串俗慈、數(shù)值、布爾類型遣耍、 null 與 undefined )之外闺阱, ES6 引入了...
    27億光年中的小小塵埃閱讀 573評論 0 0
  • 前面的話 ES5中包含5種原始類型:字符串、數(shù)字舵变、布爾值酣溃、null和undefined。ES6引入了第6種原始類型...
    CodeMT閱讀 687評論 0 1
  • 原創(chuàng)文章&經(jīng)驗總結(jié)&從校招到A廠一路陽光一路滄桑 詳情請戳www.codercc.com 主要知識點:創(chuàng)建符號值纪隙、...
    你聽___閱讀 906評論 0 1
  • 回憶一下JS中的原始類型:字符串型赊豌、數(shù)字型、布爾型绵咱、null和undefined碘饼。 ES6中引入了第6種原始類型:...
    ___Jing___閱讀 8,663評論 2 10
  • 大家好,我是王繼軍,今天我的口頭作文是我愛你艾恼。媽媽說住涉。太有多少頭發(fā)。他就有不愛我钠绍,我說說我書架上有多少書。輸液柳爽,我...
    怡紅寶玉閱讀 369評論 0 0