如何用知名Symbol黑掉JavaScript(5種方法)
他們稱(chēng)之為知名符號(hào) — 盡管大多數(shù)開(kāi)發(fā)者從未使用過(guò)它們,甚至從未聽(tīng)說(shuō)過(guò)它們。
這是一個(gè)非常酷的功能,你可以用它來(lái)實(shí)現(xiàn)這樣的魔法:
你將看到我們?nèi)绾问褂弥?Symbol 構(gòu)建這些類(lèi)來(lái)實(shí)現(xiàn)這一點(diǎn)。
它們?nèi)际顷P(guān)于完全定制內(nèi)置操作(如for..of)的正常行為。這就像C++和C#中的運(yùn)算符重載。
它們也都是Symbol類(lèi)的靜態(tài)方法。
1. Symbol.hasInstance
首先我們有Symbol.hasInstance:用于輕松改變instanceof運(yùn)算符的行為。
通常,instanceof用于檢查一個(gè)變量是否是某個(gè)類(lèi)的實(shí)例。
就像它應(yīng)該的那樣;相當(dāng)標(biāo)準(zhǔn)的東西。
但是使用Symbol.hasInstance,我們可以完全改變instanceof的工作方式:
現(xiàn)在就instanceof而言,一個(gè)Person不再是Person了。
如果我們不想完全覆蓋它,而是以一種直觀的方式擴(kuò)展它呢?
我們不能在 Symbol 內(nèi)部使用instanceof,因?yàn)槟菚?huì)很快導(dǎo)致無(wú)限遞歸:
class Person {
static [Symbol.hasInstance](instance) {
return instance instanceof Person; // 無(wú)限遞歸!
}
}
相反,我們將對(duì)象的特殊constructor屬性與我們自己的進(jìn)行比較:
如果你剛剛聽(tīng)說(shuō).constructor,這應(yīng)該解釋一切:
2. Symbol.iterator
我們的下一個(gè)黑客技巧是Symbol.iterator,用于完全改變循環(huán)如何以及是否在對(duì)象上工作。
還記得這個(gè)嗎:
我們通過(guò)Symbol.iterator實(shí)現(xiàn)了這一點(diǎn):
我們?cè)俅慰吹缴善鞒霈F(xiàn)。
每當(dāng)我們使用for..of時(shí)。
這在幕后發(fā)生:
因此,通過(guò)Symbol.iterator,我們完全改變了for..of對(duì)任何List對(duì)象的操作:
3. Symbol.toPrimitive
使用Symbol.toPrimitive,我們可以快速?gòu)倪@個(gè):
變成這個(gè):
我們通過(guò)覆蓋Symbol.toPrimitive實(shí)現(xiàn)了這一點(diǎn):
現(xiàn)在我們可以在任何使用字符串進(jìn)行插值和連接的地方使用Person對(duì)象:
甚至還有一個(gè)hint參數(shù),可以使對(duì)象表現(xiàn)得像number、string或其他東西。
4. Symbol.split
天才的知名 Symbol,用于將你的自定義對(duì)象轉(zhuǎn)換為字符串分隔符:
5. Symbol.search
就像Symbol.split一樣,將你的自定義對(duì)象轉(zhuǎn)換為復(fù)雜的字符串搜索工具:
最后的思考
從循環(huán)到分割再到搜索,知名符號(hào)讓我們可以重新定義我們的核心功能,使它們以獨(dú)特和令人愉快的方式運(yùn)行,推動(dòng)了JavaScript可能性的邊界。