javascript - 奇怪的Symbol的問題
問題描述
這是抽出來的兩行代碼 var name = Symbol(’test’) 一直提示 無法轉(zhuǎn)換,是關(guān)鍵字保留?還是其他原因?為什么換一個(gè)var name1 = Symbol(’test’)卻可以通過編譯?其他普通的var s1 s2也可通過編譯。
問題解答
回答1:這問題挺有意思的,我也從來沒有注意到,翻了翻資料,發(fā)現(xiàn)原來是很多事情巧合的湊合到一塊兒,然后出現(xiàn)了這個(gè)問題。準(zhǔn)確的來說,是瀏覽器的默認(rèn)行為和JavaScript的隱式類型變換搗的鬼。
一點(diǎn)一點(diǎn)來,首先,var和let的區(qū)別在哪里?
var聲明的變量會(huì)被提升至當(dāng)前函數(shù)作用域頂端,如果是在全局那么這個(gè)變量將會(huì)成為window的一個(gè)屬性。 而對(duì)于let聲明的變量,它會(huì)將變量提升至當(dāng)前塊級(jí)作用域,并且如果是在全局,當(dāng)前變量也不會(huì)成為window的屬性。
所以,在全局中會(huì)出現(xiàn)這樣的事情:
var test1 = ’test1’;let test2 = ’test2’;console.log(window.test1); // test1console.log(window.test2); // undefined
然后,name為名的變量和別的變量有什么區(qū)別? 上面我們知道了,var name = ’test1’;實(shí)際上可以等同于window.name = ’test1’,很容易就能想到,name是不是固定的保留字?
翻翻規(guī)范,還真是的。 window.name屬性表示的是當(dāng)前窗口上下文的名稱。下面是window的部分接口:
[ReplaceableNamedProperties] interface Window { // the current browsing context readonly attribute WindowProxy window; readonly attribute WindowProxy self; readonly attribute Document document; attribute DOMString name; //..}
name屬性在這里的最后一行,沒有readonly的前綴,說明它是可讀可寫的,它的數(shù)據(jù)類型則是DOMString。 DOMString是指UTF-16的字符串,在JavaScript中它會(huì)直接映射到String。
所以當(dāng)我們給window.name賦值的時(shí)候,這個(gè)值會(huì)被強(qiáng)制轉(zhuǎn)換為String。
我們可以試試看:
var name = { a:1, b:2 };console.log(window.name); // [object Object]var name = [0, 1, 2, 3];console.log(window.name); // 0,1,2,3
到了這里大概就能猜到,var name = Symbol(’test’);的錯(cuò)誤,應(yīng)該是Symbol變量在做類型轉(zhuǎn)換的時(shí)候出了問題。而實(shí)際報(bào)的錯(cuò)誤也證實(shí)了我們的猜測(cè):TypeError: Cannot convert a Symbol value to a string。
但是,似乎不太對(duì),Symbol變量是可以轉(zhuǎn)換成字符串的啊,比如:
let test = Symbol(’test’);console.log(test.toString()); // Symbol(test)console.log(String(test)); // Symbol(test)
嘛,這就是比較老生常談的東西了,JavaScript的隱式類型變換和顯式的強(qiáng)制轉(zhuǎn)換對(duì)于部分變量是不同的。很不幸,在這里Symbol就是這么一類。
Symbol被隱式的轉(zhuǎn)換時(shí),它會(huì)首先調(diào)用其內(nèi)部的ToPrimitive接口,拿到其原始值,然后在其中再調(diào)用ToString函數(shù)轉(zhuǎn)換為字符串。注意,這里的這個(gè)ToString函數(shù)是其內(nèi)部的抽象方法,和暴露在外的Symbol.prototype.toString()不是一個(gè)東西。
對(duì)于Symbol變量而言,當(dāng)其調(diào)用ToString的時(shí)候就會(huì)報(bào)錯(cuò),更詳細(xì)的我就不展開了,有興趣的可以自己看看規(guī)范:ToString ( argument )。
回答2:我剛剛也在控制臺(tái)試了一下,確實(shí)是個(gè)很神奇的BUG,不過你將
var name = Symbol('test'); //改成let name = Symbol('test'); //試試。。
然后驚奇的發(fā)現(xiàn)BUG又沒了。。我猜跟瀏覽器是怎么解析語法有關(guān),但這些東西我也不懂啊。
回答3:name是window的特有屬性,如果你換個(gè)變量試試就不會(huì)報(bào)錯(cuò)了。。。
回答4:name 是 window 的特有屬性,在全局環(huán)境下定義的name變量,賦任何值都會(huì)自動(dòng)轉(zhuǎn)化成字符串,而Symbol類型不能直接轉(zhuǎn)化為字符串,所以報(bào)錯(cuò)了。
你可以
var name = 1;console.log(name);
就知道了。
相關(guān)文章:
1. python - beautifulsoup獲取網(wǎng)頁內(nèi)容的問題2. Docker for Mac 創(chuàng)建的dnsmasq容器連不上/不工作的問題3. docker鏡像push報(bào)錯(cuò)4. docker - 如何修改運(yùn)行中容器的配置5. docker-machine添加一個(gè)已有的docker主機(jī)問題6. fragment - android webView 返回后怎么禁止重新渲染?7. docker不顯示端口映射呢?8. android studio總是在processes running好久9. dockerfile - [docker build image失敗- npm install]10. angular.js - Angular 2 + Django構(gòu)建的Web應(yīng)用, 如何合理搭配 ?
