By Viral Shah | Nov 26, 2018
js一門很容易入門但是很難精通的語言。我很認(rèn)同這句話。這是因?yàn)閖s是一門古老的語言同時(shí)也是一門很靈活的語言。有著一堆神秘的語法和過時(shí)的功能。我已經(jīng)使用js很多年了,迄今為止,我時(shí)不時(shí)地會(huì)發(fā)現(xiàn)一些我從未知道的隱藏語法或技巧。

我試圖列出一些鮮為人知的js特性。雖然有一些特性在嚴(yán)格模式下是不能用的,但是它依然是一種不錯(cuò)的js特性。然而,請(qǐng)注意,我不建議你全使用上我介紹的特性。雖然它們很酷,但畢竟是鮮為人知的特性,你的同事可能會(huì)看不懂。
void 操作符
js有一元運(yùn)算符。你可能已經(jīng)見過了,像 void(0) 或者 void0 。它只有一個(gè)目的 - 在右邊評(píng)估表達(dá)式并返回undefined。使用0只是一種慣例。不一定要使用0.它可以是任何有效的表達(dá)式,如
void <expression>
它仍然返回undefined。

為什么要這樣子返回undefined,直接返回undefined不好么?看起來這個(gè)特性很多余,不是么?
有趣的事實(shí)
好吧,事實(shí)證明,在ES5之前,你實(shí)際上可以在大多數(shù)瀏覽器中為undefined重新分配值。類似這樣
undefined =“abc”
使用void的話會(huì)始終保持返回正確的undefined。
構(gòu)造函數(shù)的括號(hào)是可選的
對(duì)的,你沒看錯(cuò),當(dāng)調(diào)用構(gòu)造函數(shù)的時(shí)候,我們?cè)陬惷竺婕拥膱A括號(hào)——完全是可選的!??(前提是你不需要傳遞參數(shù))
下面的代碼樣式都被認(rèn)為是有效的JS語法,并且會(huì)給你完全相同的結(jié)果!

IIFE的括號(hào)可以被跳過
IIFE的語法讓我感覺總是有點(diǎn)奇怪。
IIFE所有的括號(hào)都有什么用?
那些額外的括號(hào)只是為了告訴js解析器,即將到來的代碼是函數(shù)表達(dá)式而不是函數(shù)。知道了這些,來想一想,有很多方法可以跳過這些額外的括號(hào),仍然可以制作有效的IIFE。

void操作符告訴解析器這段代碼是函數(shù)表達(dá)式。因此,我們可以省略包著函數(shù)的括號(hào)。你猜怎么著?我們可以使用任何一元運(yùn)算符(void,+ ,!, - 等),這仍然有效。
真酷!
然而,如果你觀察再仔細(xì)點(diǎn),你會(huì)有個(gè)疑問,
一元運(yùn)算符不會(huì)影響IIFE返回的結(jié)果嗎?
好吧,它會(huì)影響結(jié)果。但是有個(gè)好消息,如果你關(guān)心返回的結(jié)果并且把結(jié)果放在某個(gè)變量中,那么你首先不需要額外的括號(hào)。
這就對(duì)了!

我們添加這些括號(hào)只是為了更好的代碼可讀性。
with 聲明
你知道js有with聲明塊?with一直是js的關(guān)鍵詞。語法如下:
with (object)
statement
// for multiple statements add a block
with (object) {
statement
statement
...
}
with可以對(duì)傳遞過來的對(duì)象進(jìn)行解析,在with 塊里可以直接使用對(duì)象的屬性。

有趣的事實(shí)
with塊看起來很酷對(duì)不對(duì)?甚至比object destructuring還好。
但是,并不是這樣的。
通常不鼓勵(lì)使用with語句,因?yàn)樗驯粭売谩?在嚴(yán)格模式下完全禁止。 事實(shí)證明,with塊會(huì)增加語言中的一些性能和安全性問題。Bummer
構(gòu)造函數(shù)
function語句并不是定義新函數(shù)的唯一方法;你可以使用【Function()】這個(gè)構(gòu)造函數(shù)和new運(yùn)算符動(dòng)態(tài)定義函數(shù)。

構(gòu)造函數(shù)的最后一個(gè)參數(shù)是字符串化代碼,就是你寫的函數(shù)。其他參數(shù)是該函數(shù)的參數(shù)。
有趣的事實(shí)
在js,F(xiàn)unction構(gòu)造函數(shù)是所有構(gòu)造函數(shù)的構(gòu)造函數(shù)。也包括Object的構(gòu)造函數(shù)。并且Function構(gòu)造函數(shù)的構(gòu)造函數(shù)就是它自身。因此,調(diào)用object.constructor.constructor...足夠多次后,在js中,最終會(huì)在任何對(duì)象返回Function構(gòu)造函數(shù)。
Function 的屬性
我們知道在js中,F(xiàn)unctions是首個(gè)對(duì)象。因此,沒有人能阻止我們?cè)贔unction對(duì)象上添加自己的屬性。這是可以的,但是很少會(huì)這樣做。
那有什么場(chǎng)景會(huì)應(yīng)用到呢?
有一些很好的用例。例如,
讓Functions可配置化
我們有個(gè)greet函數(shù)。我們想要讓我們的函數(shù)在不同的環(huán)境下打印不同語言的問候語。這個(gè)環(huán)境是可以配置的。我們可以在某處維護(hù)個(gè)全局環(huán)境變量,或者使用上文所說的添加自定義屬性

Function的靜態(tài)變量
另一個(gè)相似的例子。假設(shè)你想要實(shí)現(xiàn)一個(gè)生成一系列有序數(shù)字的數(shù)字生成器。通常來說,你會(huì)用Class或者IIFE,在里面維護(hù)一個(gè)計(jì)數(shù)變量,然后輸出有序的值。這樣我們就可以限制對(duì)計(jì)數(shù)器的訪問,并避免使用額外的變量來污染全局空間。
但是,如果我們希望靈活地讀取甚至修改計(jì)數(shù)器并且不污染全局空間呢?
好吧,我們?nèi)匀豢梢詣?chuàng)建一個(gè)Class,帶有一個(gè)計(jì)數(shù)器變量和一些額外的方法來讀取它; 或者我們可以懶一點(diǎn),只需在函數(shù)上使用屬性。

現(xiàn)在是中場(chǎng)休息時(shí)間,我們等你回來。如果你想接著繼續(xù),你是一個(gè)勇敢的戰(zhàn)士,我向你致敬。
繼續(xù)吧
Arguments屬性
我相信大多數(shù)人都知道函數(shù)中的參數(shù)對(duì)象。 它是一個(gè)像對(duì)象一樣的數(shù)組(譯者:emmm),在所有函數(shù)中都能訪問到。它具有在調(diào)用函數(shù)時(shí)傳遞的參數(shù)列表,也有其他一些有趣的屬性。
- arguments.callee:指向當(dāng)前調(diào)用函數(shù)
- arguments.callee.caller:指向當(dāng)前被調(diào)函數(shù)的調(diào)用者。

注意:雖然ES5禁止在嚴(yán)格模式下使用callee和caller,但在許多編譯庫中仍然常見。 所以,值得學(xué)習(xí)它們。
標(biāo)記模版字面量
除非你是井底之蛙,你一定聽說過模版字面量。模版字面量時(shí)es6的一個(gè)很酷的補(bǔ)充。然而,你聽說過Tagged模版字面量么(Tagged Template Literals)?

Tagged模板字面量允許您通過向模板字面量添加自定義標(biāo)記來更好地控制將模板字面量解析為字符串。Tagged只是一個(gè)獲取字符串模板解析后的所有字符串和值的數(shù)組的解析器函數(shù)。Tagged函數(shù)最終返回字符串。
在下面的示例中,我們的自定義標(biāo)記 - highlight,解釋模板文字的值,并使用
<mark>
元素將解釋的值包裝在結(jié)果字符串中,以突出顯示。

Getter & Setter
在大多數(shù)情況下,js對(duì)象時(shí)很簡(jiǎn)單的。比如說有一個(gè)對(duì)象叫user,我們嘗試使用user.age來讀取age屬性時(shí),如果有定義并賦值了,就有返回。如果沒有,就返回undefined。簡(jiǎn)單。
但是,它不一定非常簡(jiǎn)單。 JavaScript對(duì)象具有Getters和Setter的概念。 我們可以編寫自定義的Getter函數(shù)來返回我們想要的任何內(nèi)容,而不是直接返回對(duì)象上的值。 設(shè)置值也是一樣的。
這使我們可以在獲取或設(shè)置屬性時(shí)可以靈活的創(chuàng)造虛擬屬性、驗(yàn)證屬性。

Getters和Setters不是es5的特性,它們是一直都存在的特性。es5只是添加了語法糖。
逗號(hào)操作符
JavaScript有一個(gè)逗號(hào)運(yùn)算符。 它允許我們?cè)谝恍兄芯帉懹啥禾?hào)分隔的多個(gè)表達(dá)式,并返回最后一個(gè)表達(dá)式的結(jié)果
// syntax
let result = expression1, expression2,... expressionN
來看看上面的例子,這里將會(huì)解析所有的表達(dá)式,并把result變量賦予expressionN返回的值。
你可能在循環(huán)里面使用過了
for (var a = 0, b = 10; a <= 10; a++, b--)
它可以幫助我們把語句寫在一行
function getNextValue() {
return counter++, console.log(counter), counter
}
或者寫lamda表達(dá)式
const getSquare = x => (console.log (x), x * x)
+ 加操作符
想要知道如何便捷地把字符串轉(zhuǎn)換成number?
只要在字符串前面加個(gè)+號(hào)。
Plus運(yùn)算符也適用于負(fù),八進(jìn)制,十六進(jìn)制,指數(shù)值。 更重要的是,它甚至可以將Date或Moment.js對(duì)象轉(zhuǎn)換為時(shí)間戳!

!! Bang Bang 操作符
好的,嚴(yán)格來講,它不是一個(gè)單獨(dú)的JavaScript運(yùn)算符。 它只是兩次使用的JavaScript否定運(yùn)算符。
但是Bang Bang聽起來很酷!Bang Bang是一個(gè)可以講任何表達(dá)式轉(zhuǎn)換成布爾值的方法。
如果表達(dá)式是一個(gè)true,則返回true;否則返回false。

~ 位運(yùn)算作符
來看一個(gè)沒人關(guān)注的位運(yùn)算操作符。我們什么時(shí)候用它呢?
好吧,有個(gè)日常用例。
當(dāng)與數(shù)字一起使用時(shí),Tilde運(yùn)算符有效,像這樣
~N => -(N + 1)。
僅當(dāng)N == -1時(shí),此表達(dá)式的計(jì)算結(jié)果為“0”
我們可以通過在indexOf(...)函數(shù)前面放置?來進(jìn)行布爾檢查是否有一項(xiàng)存在。String或Array中都可以用這個(gè)。

注意:ES6和ES7分別在String&Array中添加了一個(gè)新的.includes()方法。當(dāng)然,它比位運(yùn)算運(yùn)算符更清晰,以檢查項(xiàng)目是否存在于Array或String中。
標(biāo)簽語句
js具有標(biāo)簽語句的概念。它允許我們?cè)趈s中命名循環(huán)和塊。然后,我們可以使用這些標(biāo)簽在使用break或continue時(shí)使用。
帶標(biāo)簽的語句在嵌套循環(huán)中特別方便。但是我們也可以使用它們來簡(jiǎn)單地將代碼組織成塊或創(chuàng)建一個(gè)可退出的塊

注意:不像其他的語言,js沒有g(shù)oto語句。因此,我們只能使用labels來搭配break和continue使用。