你不懂JS:ES6與未來 第二章:語法(下)

官方中文版原文鏈接

感謝社區(qū)中各位的大力支持械姻,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大獎(jiǎng):點(diǎn)擊這里領(lǐng)取

數(shù)字字面量擴(kuò)展

在ES5之前葫慎,數(shù)字字面量看起來就像下面的東西 —— 八進(jìn)制形式?jīng)]有被官方指定塑径,唯一被允許的是各種瀏覽器已經(jīng)實(shí)質(zhì)上達(dá)成一致的一種擴(kuò)展:

var dec = 42,
    oct = 052,
    hex = 0x2a;

注意: 雖然你用不同的進(jìn)制來指定一個(gè)數(shù)字女坑,但是數(shù)字的數(shù)學(xué)值才是被存儲(chǔ)的東西,而且默認(rèn)的輸出解釋方式總是10進(jìn)制的晓勇。前面代碼段中的三個(gè)變量都在它們當(dāng)中存儲(chǔ)了值42堂飞。

為了進(jìn)一步說明052是一種非標(biāo)準(zhǔn)形式擴(kuò)展,考慮如下代碼:

Number( "42" );             // 42
Number( "052" );            // 52
Number( "0x2a" );           // 42

ES5繼續(xù)允許這種瀏覽器擴(kuò)展的八進(jìn)制形式(包括這樣的不一致性)绑咱,除了在strict模式下绰筛,八進(jìn)制字面量(052)是不允許的。做出這種限制的主要原因是描融,許多開發(fā)者似乎習(xí)慣于下意識(shí)地為了將代碼對(duì)齊而在十進(jìn)制的數(shù)字前面前綴0铝噩,然后遭遇他們完全改變了數(shù)字的值的意外!

ES6延續(xù)了除十進(jìn)制數(shù)字之外的數(shù)字字面量可以被表示的遺留的改變/種類×耍現(xiàn)在有了一種官方的八進(jìn)制形式骏庸,一種改進(jìn)了的十六進(jìn)制形式,和一種全新的二進(jìn)制形式年叮。由于Web兼容性的原因具被,在非strict模式下老式的八進(jìn)制形式052將繼續(xù)是合法的,但其實(shí)應(yīng)當(dāng)永遠(yuǎn)不再被使用了只损。

這些是新的ES6數(shù)字字面形式:

var dec = 42,
    oct = 0o52,         // or `0O52` :(
    hex = 0x2a,         // or `0X2a` :/
    bin = 0b101010;     // or `0B101010` :/

唯一允許的小數(shù)形式是十進(jìn)制的一姿。八進(jìn)制,十六進(jìn)制跃惫,和二進(jìn)制都是整數(shù)形式叮叹。

而且所有這些形式的字符串表達(dá)形式都是可以被強(qiáng)制轉(zhuǎn)換/變換為它們的數(shù)字等價(jià)物的:

Number( "42" );         // 42
Number( "0o52" );       // 42
Number( "0x2a" );       // 42
Number( "0b101010" );   // 42

雖然嚴(yán)格來說不是ES6新增的,但一個(gè)鮮為人知的事實(shí)是你其實(shí)可以做反方向的轉(zhuǎn)換(好吧爆存,某種意義上的):

var a = 42;

a.toString();           // "42" —— 也可使用`a.toString( 10 )`
a.toString( 8 );        // "52"
a.toString( 16 );       // "2a"
a.toString( 2 );        // "101010"

事實(shí)上蛉顽,以這種方你可以用從236的任何進(jìn)制表達(dá)一個(gè)數(shù)字,雖然你會(huì)使用標(biāo)準(zhǔn)進(jìn)制 —— 2先较,8携冤,10,和16 ——之外的情況非常少見闲勺。

Unicode

我只能說這一節(jié)不是一個(gè)窮盡了“關(guān)于Unicode你想知道的一切”的資料曾棕。我想講解的是,你需要知道在ES6中對(duì)Unicode改變了什么霉翔,但是我們不會(huì)比這深入太多睁蕾。Mathias Bynens (http://twitter.com/mathias) 大量且出色地撰寫/講解了關(guān)于JS和Unicode (參見 https://mathiasbynens.be/notes/javascript-unicodehttp://fluentconf.com/javascript-html-2015/public/content/2015/02/18-javascript-loves-unicode)。

0x00000xFFFF范圍內(nèi)的Unicode字符包含了所有的標(biāo)準(zhǔn)印刷字符(以各種語言),它們都是你可能看到過和互動(dòng)過的子眶。這組字符被稱為 基本多文種平面(Basic Multilingual Plane (BMP))瀑凝。BMP甚至包含像這個(gè)酷雪人一樣的有趣字符: ? (U+2603)。

在這個(gè)BMP集合之外還有許多擴(kuò)展的Unicode字符臭杰,它們的范圍一直到0x10FFFF粤咪。這些符號(hào)經(jīng)常被稱為 星形(astral) 符號(hào),這正是BMP之外的字符的16組 平面 (也就是渴杆,分層/分組)的名稱寥枝。星形符號(hào)的例子包括?? (U+1D11E)和?? (U+1F4A9)。

在ES6之前磁奖,JavaScript字符串可以使用Unicode轉(zhuǎn)義來指定Unicode字符囊拜,例如:

var snowman = "\u2603";
console.log( snowman );         // "?"

然而实夹,\uXXXXUnicode轉(zhuǎn)義僅支持四個(gè)十六進(jìn)制字符绳泉,所以用這種方式表示你只能表示BMP集合中的字符。要在ES6以前使用Unicode轉(zhuǎn)義表示一個(gè)星形字符厨诸,你需要使用一個(gè) 代理對(duì)(surrogate pair) —— 基本上是兩個(gè)經(jīng)特殊計(jì)算的Unicode轉(zhuǎn)義字符放在一起身诺,被JS解釋為一個(gè)單獨(dú)星形字符:

var gclef = "\uD834\uDD1E";
console.log( gclef );           // "??"

在ES6中蜜托,我們現(xiàn)在有了一種Unicode轉(zhuǎn)義的新形式(在字符串和正則表達(dá)式中),稱為Unicode 代碼點(diǎn)轉(zhuǎn)義

var gclef = "\u{1D11E}";
console.log( gclef );           // "??"

如你所見霉赡,它的區(qū)別是出現(xiàn)在轉(zhuǎn)義序列中的{ }橄务,它允許轉(zhuǎn)義序列中包含任意數(shù)量的十六進(jìn)制字符。因?yàn)槟阒恍枰鶄€(gè)就可以表示在Unicode中可能的最高代碼點(diǎn)(也就是穴亏,0x10FFFF)蜂挪,所以這是足夠的。

Unicode敏感的字符串操作

在默認(rèn)情況下迫肖,JavaScript字符串操作和方法對(duì)字符串值中的星形符號(hào)是不敏感的锅劝。所以攒驰,它們獨(dú)立地處理每個(gè)BMP字符蟆湖,即便是可以組成一個(gè)單獨(dú)字符的兩半代理〔7啵考慮如下代碼:

var snowman = "?";
snowman.length;                 // 1

var gclef = "??";
gclef.length;                   // 2

那么隅津,我們?nèi)绾尾拍苷_地計(jì)算這樣的字符串的長度呢?在這種場景下劲室,下面的技巧可以工作:

var gclef = "??";

[...gclef].length;              // 1
Array.from( gclef ).length;     // 1

回想一下本章早先的“for..of循環(huán)”一節(jié)伦仍,ES6字符串擁有內(nèi)建的迭代器。這個(gè)迭代器恰好是Unicode敏感的很洋,這意味著它將自動(dòng)地把一個(gè)星形符號(hào)作為一個(gè)單獨(dú)的值輸出充蓝。我們?cè)谝粋€(gè)數(shù)組字面量上使用擴(kuò)散操作符...,利用它創(chuàng)建了一個(gè)字符串符號(hào)的數(shù)組。然后我們只需檢查這個(gè)結(jié)果數(shù)組的長度谓苟。ES6的Array.from(..)基本上與[...XYZ]做的事情相同官脓,不過我們將在第六章中講解這個(gè)工具的細(xì)節(jié)。

警告: 應(yīng)當(dāng)注意的是涝焙,相對(duì)地講卑笨,與理論上經(jīng)過優(yōu)化的原生工具/屬性將做的事情比起來,僅僅為了得到一個(gè)字符串的長度就構(gòu)建并耗盡一個(gè)迭代器在性能上的代價(jià)是高昂的仑撞。

不幸的是赤兴,完整的答案并不簡單或直接。除了代理對(duì)(字符串迭代器可以搞定的)隧哮,一些特殊的Unicode代碼點(diǎn)有其他特殊的行為桶良,解釋起來非常困難。例如沮翔,有一組代碼點(diǎn)可以修改前一個(gè)相鄰的字符艺普,稱為 組合變音符號(hào)(Combining Diacritical Marks)

考慮這兩個(gè)數(shù)組的輸出:

console.log( s1 );              // "é"
console.log( s2 );              // "é"

它們看起來一樣,但它們不是鉴竭!這是我們?nèi)绾蝿?chuàng)建s1s2的:

var s1 = "\xE9",
    s2 = "e\u0301";

你可能猜到了歧譬,我們前面的length技巧對(duì)s2不管用:

[...s1].length;                 // 1
[...s2].length;                 // 2

那么我們能做什么?在這種情況下搏存,我們可以使用ES6的String#normalize(..)工具瑰步,在查詢這個(gè)值的長度前對(duì)它實(shí)施一個(gè) Unicode正規(guī)化操作

var s1 = "\xE9",
    s2 = "e\u0301";

s1.normalize().length;          // 1
s2.normalize().length;          // 1

s1 === s2;                      // false
s1 === s2.normalize();          // true

實(shí)質(zhì)上,normalize(..)接受一個(gè)"e\u0301"這樣的序列璧眠,并把它正規(guī)化為\xE9缩焦。正規(guī)化甚至可以組合多個(gè)相鄰的組合符號(hào),如果存在適合他們組合的Unicode字符的話:

var s1 = "o\u0302\u0300",
    s2 = s1.normalize(),
    s3 = "?";

s1.length;                      // 3
s2.length;                      // 1
s3.length;                      // 1

s2 === s3;                      // true

不幸的是责静,這里的正規(guī)化也不完美袁滥。如果你有多個(gè)組合符號(hào)在修改一個(gè)字符,你可能不會(huì)得到你所期望的長度計(jì)數(shù)灾螃,因?yàn)橐粋€(gè)被獨(dú)立定義的题翻,可以表示所有這些符號(hào)組合的正規(guī)化字符可能不存在。例如:

var s1 = "e\u0301\u0330";

console.log( s1 );              // "e??"

s1.normalize().length;          // 2

你越深入這個(gè)兔子洞腰鬼,你就越能理解要得到一個(gè)“長度”的精確定義是很困難的嵌赠。我們?cè)谝曈X上看到的作為一個(gè)單獨(dú)字符繪制的東西 —— 更精確地說,它稱為一個(gè) 字形 —— 在程序處理的意義上不總是嚴(yán)格地關(guān)聯(lián)到一個(gè)單獨(dú)的“字符”上熄赡。

提示: 如果你就是想看看這個(gè)兔子洞有多深姜挺,看看“字形群集邊界(Grapheme Cluster Boundaries)”算法(http://www.Unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries)。

字符定位

與長度的復(fù)雜性相似彼硫,“在位置2上的字符是什么炊豪?”凌箕,這么問的意思究竟是什么?前ES6的原生答案來自charAt(..)词渤,它不會(huì)遵守一個(gè)星形字符的原子性陌知,也不會(huì)考慮組合符號(hào)。

考慮如下代碼:

var s1 = "abc\u0301d",
    s2 = "ab\u0107d",
    s3 = "ab\u{1d49e}d";

console.log( s1 );              // "ab?d"
console.log( s2 );              // "ab?d"
console.log( s3 );              // "ab??d"

s1.charAt( 2 );                 // "c"
s2.charAt( 2 );                 // "?"
s3.charAt( 2 );                 // "" <-- 不可打印的代理字符
s3.charAt( 3 );                 // "" <-- 不可打印的代理字符

那么掖肋,ES6會(huì)給我們Unicode敏感版本的charAt(..)嗎仆葡?不幸的是,不志笼。在本書寫作時(shí)沿盅,在后ES6的考慮之中有一個(gè)這樣的工具的提案。

但是使用我們?cè)谇耙还?jié)探索的東西(當(dāng)然也帶著它的限制H依!)腰涧,我們可以黑一個(gè)ES6的答案:

var s1 = "abc\u0301d",
    s2 = "ab\u0107d",
    s3 = "ab\u{1d49e}d";

[...s1.normalize()][2];         // "?"
[...s2.normalize()][2];         // "?"
[...s3.normalize()][2];         // "??"

警告: 提醒一個(gè)早先的警告:在每次你想得到一個(gè)單獨(dú)的字符時(shí)構(gòu)建并耗盡一個(gè)迭代器……在性能上不是很理想。對(duì)此紊浩,希望我們很快能在后ES6時(shí)代得到一個(gè)內(nèi)建的窖铡,優(yōu)化過的工具。

那么charCodeAt(..)工具的Unicode敏感版本呢坊谁?ES6給了我們codePointAt(..)

var s1 = "abc\u0301d",
    s2 = "ab\u0107d",
    s3 = "ab\u{1d49e}d";

s1.normalize().codePointAt( 2 ).toString( 16 );
// "107"

s2.normalize().codePointAt( 2 ).toString( 16 );
// "107"

s3.normalize().codePointAt( 2 ).toString( 16 );
// "1d49e"

那么從另一個(gè)方向呢费彼?String.fromCharCode(..)的Unicode敏感版本是ES6的String.fromCodePoint(..)

String.fromCodePoint( 0x107 );      // "?"

String.fromCodePoint( 0x1d49e );    // "??"

那么等一下,我們能組合String.fromCodePoint(..)codePointAt(..)來得到一個(gè)剛才的Unicode敏感charAt(..)的更好版本嗎口芍?是的箍铲!

var s1 = "abc\u0301d",
    s2 = "ab\u0107d",
    s3 = "ab\u{1d49e}d";

String.fromCodePoint( s1.normalize().codePointAt( 2 ) );
// "?"

String.fromCodePoint( s2.normalize().codePointAt( 2 ) );
// "?"

String.fromCodePoint( s3.normalize().codePointAt( 2 ) );
// "??"

還有好幾個(gè)字符串方法我們沒有在這里講解,包括toUpperCase()鬓椭,toLowerCase()颠猴,substring(..)indexOf(..)小染,slice(..)翘瓮,以及其他十幾個(gè)。它們中沒有任何一個(gè)為了完全支持Unicode而被改變或增強(qiáng)過裤翩,所以在處理含有星形符號(hào)的字符串是资盅,你應(yīng)當(dāng)非常小心 —— 可能干脆回避它們!

還有幾個(gè)字符串方法為了它們的行為而使用正則表達(dá)式岛都,比如replace(..)match(..)律姨。值得慶幸的是振峻,ES6為正則表達(dá)式帶來了Unicode支持臼疫,正如我們?cè)诒菊略缜暗摹癠nicode標(biāo)志”中講解過的那樣。

好了扣孟,就是這些烫堤!有了我們剛剛講過的各種附加功能,JavaScript的Unicode字符串支持要比前ES6時(shí)代好太多了(雖然還不完美)。

Unicode標(biāo)識(shí)符名稱

Unicode還可以被用于標(biāo)識(shí)符名稱(變量鸽斟,屬性拔创,等等)。在ES6之前富蓄,你可以通過Unicode轉(zhuǎn)義這么做剩燥,比如:

var \u03A9 = 42;

// 等同于:var Ω = 42;

在ES6中,你還可以使用前面講過的代碼點(diǎn)轉(zhuǎn)義語法:

var \u{2B400} = 42;

// 等同于:var ?? = 42;

關(guān)于究竟哪些Unicode字符被允許使用立倍,有一組復(fù)雜的規(guī)則灭红。另外,有些字符只要不是標(biāo)識(shí)符名稱的第一個(gè)字符就允許使用口注。

注意: 關(guān)于所有這些細(xì)節(jié)变擒,Mathias Bynens寫了一篇了不起的文章 (https://mathiasbynens.be/notes/javascript-identifiers-es6)。

很少有理由寝志,或者是為了學(xué)術(shù)上的目的娇斑,才會(huì)在標(biāo)識(shí)符名稱中使用這樣不尋常的字符。你通常不會(huì)因?yàn)橐揽窟@些深?yuàn)W的功能編寫代碼而感到舒服材部。

Symbol

在ES6中毫缆,長久以來首次,有一個(gè)新的基本類型被加入到了JavaScript:symbol乐导。但是悔醋,與其他的基本類型不同,symbol沒有字面形式兽叮。

這是你如何創(chuàng)建一個(gè)symbol:

var sym = Symbol( "some optional description" );

typeof sym;     // "symbol"

一些要注意的事情是:

  • 你不能也不應(yīng)該將newSymbol(..)一起使用芬骄。它不是一個(gè)構(gòu)造器,你也不是在產(chǎn)生一個(gè)對(duì)象鹦聪。
  • 被傳入Symbol(..)的參數(shù)是可選的账阻。如果傳入的話,它應(yīng)當(dāng)是一個(gè)字符串泽本,為symbol的目的給出一個(gè)友好的描述淘太。
  • typeof的輸出是一個(gè)新的值("symbol"),這是識(shí)別一個(gè)symbol的主要方法规丽。

如果描述被提供的話蒲牧,它僅僅用于symbol的字符串化表示:

sym.toString();     // "Symbol(some optional description)"

與基本字符串值如何不是String的實(shí)例的原理很相似,symbol也不是Symbol的實(shí)例赌莺。如果冰抢,由于某些原因,你想要為一個(gè)symbol值構(gòu)建一個(gè)封箱的包裝器對(duì)像艘狭,你可以做如下的事情:

sym instanceof Symbol;      // false

var symObj = Object( sym );
symObj instanceof Symbol;   // true

symObj.valueOf() === sym;   // true

注意: 在這個(gè)代碼段中的symObjsym是可以互換使用的挎扰;兩種形式可以在symbol被用到的地方使用翠订。沒有太多的理由要使用封箱的包裝對(duì)象形式(symObj),而不用基本類型形式(sym)遵倦。和其他基本類型的建議相似尽超,使用sym而非symObj可能是最好的。

一個(gè)symbol本身的內(nèi)部值 —— 稱為它的name —— 被隱藏在代碼之外而不能取得梧躺。你可以認(rèn)為這個(gè)symbol的值是一個(gè)自動(dòng)生成的似谁,(在你的應(yīng)用程序中)獨(dú)一無二的字符串值。

但如果這個(gè)值是隱藏且不可取得的掠哥,那么擁有一個(gè)symbol還有什么意義棘脐?

一個(gè)symbol的主要意義是創(chuàng)建一個(gè)不會(huì)和其他任何值沖突的類字符串值。所以龙致,舉例來說蛀缝,可以考慮將一個(gè)symbol用做表示一個(gè)事件的名稱的值:

const EVT_LOGIN = Symbol( "event.login" );

然后你可以在一個(gè)使用像"event.login"這樣的一般字符串字面量的地方使用EVT_LOGIN

evthub.listen( EVT_LOGIN, function(data){
    // ..
} );

其中的好處是,EVT_LOGIN持有一個(gè)不能被其他任何值所(有意或無意地)重復(fù)的值目代,所以在哪個(gè)事件被分發(fā)或處理的問題上不可能存在任何含糊屈梁。

注意: 在前面的代碼段的幕后,幾乎可以肯定地認(rèn)為evthub工具使用了EVT_LOGIN參數(shù)值的symbol值作為某個(gè)跟蹤事件處理器的內(nèi)部對(duì)象的屬性/鍵榛了。如果evthub需要將symbol值作為一個(gè)真實(shí)的字符串使用在讶,那么它將需要使用String(..)或者toString(..)進(jìn)行明確強(qiáng)制轉(zhuǎn)換,因?yàn)閟ymbol的隱含字符串強(qiáng)制轉(zhuǎn)換是不允許的霜大。

你可能會(huì)將一個(gè)symbol直接用做一個(gè)對(duì)象中的屬性名/鍵构哺,如此作為一個(gè)你想將之用于隱藏或元屬性的特殊屬性。重要的是战坤,要知道雖然你試圖這樣對(duì)待它曙强,但是它 實(shí)際上 并不是隱藏或不可接觸的屬性。

考慮這個(gè)實(shí)現(xiàn)了 單例 模式行為的模塊 —— 也就是途茫,它僅允許自己被創(chuàng)建一次:

const INSTANCE = Symbol( "instance" );

function HappyFace() {
    if (HappyFace[INSTANCE]) return HappyFace[INSTANCE];

    function smile() { .. }

    return HappyFace[INSTANCE] = {
        smile: smile
    };
}

var me = HappyFace(),
    you = HappyFace();

me === you;         // true

這里的symbol值INSTANCE是一個(gè)被靜態(tài)地存儲(chǔ)在HappyFace()函數(shù)對(duì)象上的特殊的碟嘴,幾乎是隱藏的,類元屬性囊卜。

替代性地娜扇,它本可以是一個(gè)像__instance這樣的普通屬性,而且其行為將會(huì)是一模一樣的栅组。symbol的使用僅僅增強(qiáng)了程序元編程的風(fēng)格雀瓢,將這個(gè)INSTANCE屬性與其他普通的屬性間保持隔離。

Symbol注冊(cè)表

在前面幾個(gè)例子中使用symbol的一個(gè)微小的缺點(diǎn)是玉掸,變量EVT_LOGININSTANCE不得不存儲(chǔ)在外部作用域中(甚至也許是全局作用域)刃麸,或者用某種方法存儲(chǔ)在一個(gè)可用的公共位置,這樣代碼所有需要使用這些symbol的部分都可以訪問它們排截。

為了輔助組織訪問這些symbol的代碼嫌蚤,你可以使用 全局symbol注冊(cè)表 來創(chuàng)建symbol辐益。例如:

const EVT_LOGIN = Symbol.for( "event.login" );

console.log( EVT_LOGIN );       // Symbol(event.login)

和:

function HappyFace() {
    const INSTANCE = Symbol.for( "instance" );

    if (HappyFace[INSTANCE]) return HappyFace[INSTANCE];

    // ..

    return HappyFace[INSTANCE] = { .. };
}

Symbol.for(..)查詢?nèi)謘ymbol注冊(cè)表來查看一個(gè)symbol是否已經(jīng)使用被提供的說明文本存儲(chǔ)過了断傲,如果有就返回它脱吱。如果沒有,就創(chuàng)建一個(gè)并返回认罩。換句話說箱蝠,全局symbol注冊(cè)表通過描述文本將symbol值看作它們本身的單例。

但這也意味著只要使用匹配的描述名垦垂,你的應(yīng)用程序的任何部分都可以使用Symbol.for(..)從注冊(cè)表中取得symbol宦搬。

諷刺的是,基本上symbol的本意是在你的應(yīng)用程序中取代 魔法字符串 的使用(被賦予了特殊意義的隨意的字符串值)劫拗。但是你正是在全局symbol注冊(cè)表中使用 魔法 描述字符串值來唯一識(shí)別/定位它們的间校!

為了避免意外的沖突,你可能想使你的symbol描述十分獨(dú)特页慷。這么做的一個(gè)簡單的方法是在它們之中包含前綴/環(huán)境/名稱空間的信息憔足。

例如,考慮一個(gè)像下面這樣的工具:

function extractValues(str) {
    var key = Symbol.for( "extractValues.parse" ),
        re = extractValues[key] ||
            /[^=&]+?=([^&]+?)(?=&|$)/g,
        values = [], match;

    while (match = re.exec( str )) {
        values.push( match[1] );
    }

    return values;
}

我們使用魔法字符串值"extractValues.parse"酒繁,因?yàn)樵谧?cè)表中的其他任何symbol都不太可能與這個(gè)描述相沖突滓彰。

如果這個(gè)工具的一個(gè)用戶想要覆蓋這個(gè)解析用的正則表達(dá)式,他們也可以使用symbol注冊(cè)表:

extractValues[Symbol.for( "extractValues.parse" )] =
    /..some pattern../g;

extractValues( "..some string.." );

除了symbol注冊(cè)表在全局地存儲(chǔ)這些值上提供的協(xié)助以外州袒,我們?cè)谶@里看到的一切其實(shí)都可以通過將魔法字符串"extractValues.parse"作為一個(gè)鍵揭绑,而不是一個(gè)symbol,來做到郎哭。這其中在元編程的層次上的改進(jìn)要多于在函數(shù)層次上的改進(jìn)他匪。

你可能偶然會(huì)使用一個(gè)已經(jīng)被存儲(chǔ)在注冊(cè)表中的symbol值來查詢它底層存儲(chǔ)了什么描述文本(鍵)。例如夸研,因?yàn)槟銦o法傳遞symbol值本身诚纸,你可能需要通知你的應(yīng)用程序的另一個(gè)部分如何在注冊(cè)表中定位一個(gè)symbol。

你可以使用Symbol.keyFor(..)取得一個(gè)被注冊(cè)的symbol描述文本(鍵):

var s = Symbol.for( "something cool" );

var desc = Symbol.keyFor( s );
console.log( desc );            // "something cool"

// 再次從注冊(cè)表取得symbol
var s2 = Symbol.for( desc );

s2 === s;                       // true

Symbols作為對(duì)象屬性

如果一個(gè)symbol被用作一個(gè)對(duì)象的屬性/鍵陈惰,它會(huì)被以一種特殊的方式存儲(chǔ)畦徘,以至這個(gè)屬性不會(huì)出現(xiàn)在這個(gè)對(duì)象屬性的普通枚舉中:

var o = {
    foo: 42,
    [ Symbol( "bar" ) ]: "hello world",
    baz: true
};

Object.getOwnPropertyNames( o );    // [ "foo","baz" ]

要取得對(duì)象的symbol屬性:

Object.getOwnPropertySymbols( o );  // [ Symbol(bar) ]

這表明一個(gè)屬性symbol實(shí)際上不是隱藏的或不可訪問的,因?yàn)槟憧偸强梢栽?code>Object.getOwnPropertySymbols(..)的列表中看到它抬闯。

內(nèi)建Symbols

ES6帶來了好幾種預(yù)定義的內(nèi)建symbol井辆,它們暴露了在JavaScript對(duì)象值上的各種元行為。然而溶握,正如人們所預(yù)料的那樣杯缺,這些symbol 沒有 沒被注冊(cè)到全局symbol注冊(cè)表中。

取而代之的是睡榆,它們作為屬性被存儲(chǔ)到了Symbol函數(shù)對(duì)象中萍肆。例如袍榆,在本章早先的“for..of”一節(jié)中,我們介紹了值Symbol.iterator

var a = [1,2,3];

a[Symbol.iterator];         // native function

語言規(guī)范使用@@前綴注釋指代內(nèi)建的symbol塘揣,最常見的幾個(gè)是:@@iterator包雀,@@toStringTag@@toPrimitive亲铡。還定義了幾個(gè)其他的symbol才写,雖然他們可能不那么頻繁地被使用。

注意: 關(guān)于這些內(nèi)建symbol如何被用于元編程的詳細(xì)信息奖蔓,參見第七章的“通用Symbol”赞草。

復(fù)習(xí)

ES6給JavaScript增加了一堆新的語法形式,有好多東西要學(xué)吆鹤!

這些東西中的大多數(shù)都是為了緩解常見編程慣用法中的痛點(diǎn)而設(shè)計(jì)的厨疙,比如為函數(shù)參數(shù)設(shè)置默認(rèn)值和將“剩余”的參數(shù)收集到一個(gè)數(shù)組中。解構(gòu)是一個(gè)強(qiáng)大的工具疑务,用來更簡約地表達(dá)從數(shù)組或嵌套對(duì)象的賦值沾凄。

雖然像箭頭函數(shù)=>這樣的特性看起來也都是關(guān)于更簡短更好看的語法,但是它們實(shí)際上擁有非常特殊的行為暑始,你應(yīng)當(dāng)在恰當(dāng)?shù)那闆r下有意地使用它們搭独。

擴(kuò)展的Unicode支持,新的正則表達(dá)式技巧廊镜,和新的symbol基本類型充實(shí)了ES6語法的發(fā)展演變牙肝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嗤朴,隨后出現(xiàn)的幾起案子配椭,更是在濱河造成了極大的恐慌,老刑警劉巖雹姊,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件股缸,死亡現(xiàn)場離奇詭異,居然都是意外死亡吱雏,警方通過查閱死者的電腦和手機(jī)敦姻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來歧杏,“玉大人镰惦,你說我怎么就攤上這事∪蓿” “怎么了旺入?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我茵瘾,道長礼华,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任拗秘,我火速辦了婚禮圣絮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘聘殖。我一直安慰自己晨雳,他們只是感情好行瑞,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布奸腺。 她就那樣靜靜地躺著,像睡著了一般血久。 火紅的嫁衣襯著肌膚如雪突照。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天氧吐,我揣著相機(jī)與錄音讹蘑,去河邊找鬼。 笑死筑舅,一個(gè)胖子當(dāng)著我的面吹牛座慰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播翠拣,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼版仔,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了误墓?” 一聲冷哼從身側(cè)響起蛮粮,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谜慌,沒想到半個(gè)月后然想,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡欣范,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年变泄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恼琼。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡妨蛹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出驳癌,到底是詐尸還是另有隱情滑燃,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布颓鲜,位于F島的核電站表窘,受9級(jí)特大地震影響典予,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜乐严,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一瘤袖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昂验,春花似錦捂敌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至甫恩,卻和暖如春逆济,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背磺箕。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工奖慌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人松靡。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓简僧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親雕欺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子岛马,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

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

  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券阅茶,享受所有官網(wǎng)優(yōu)惠蛛枚,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 2,892評(píng)論 0 16
  • 特別說明,為便于查閱脸哀,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 443評(píng)論 0 0
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持蹦浦,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠撞蜂,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 6,541評(píng)論 3 22
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持盲镶,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠蝌诡,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 2,334評(píng)論 2 24
  • 概述:主要講述矩陣變換與圖形變化的聯(lián)系,逐步將矩陣應(yīng)用到動(dòng)畫編程,重點(diǎn)講述透視變換 M34;參考文獻(xiàn): (3D數(shù)學(xué)...
    hehtao閱讀 1,814評(píng)論 0 2