- 原文地址:What's the longest keyword sequence in Javascript?
- 原文作者:Leo Horie
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:xionglong58
- 校對者:Endone, Jingyuan0000
最近有幾個關於使用 Javascript 編寫最長關鍵字序列的挑戰。
但問題是:
讓我們試試能不能做的更好。
(但是我們首先要回顧一些基礎規則)
規則
- 程式碼必須能作為有效的 Javascript 進行解析和執行。不能忽略 early errors
- 只允許使用關鍵字
- 除小寫字母外,其它唯一允許的字元是空格
- 不能在序列中重複使用一個關鍵字
- 您可以根據需要新增儘可能多的前同步碼和後同步碼
額外挑戰
- 關鍵字之間允許換行
- 允許使用類似關鍵字的標記
進入正題
@arjunb_msft 提出的最長 15 個關鍵字的程式
function *f() {
if (1);
else do return yield delete true instanceof typeof void new class extends false in this {}; while (1)
}
複製程式碼
不幸的是,他的方法裡使用了保留字 true
和 false
,而兩者實際上不是關鍵字。在 Chrome 中執行程式也會丟擲一個錯誤:“Uncaught SyntaxError: Unexpected token in”。
@bluepnume 提出 15 個關鍵字的方案是:
async function* foo() {
return yield delete void await null in this instanceof typeof new class extends async function () {} {}
}
複製程式碼
這段程式可以在 Chrome 中執行,但是程式中使用了 null
,這也不是一個關鍵字。
雖然有些賣弄,如果我們從第二個解決方案中剔除 null
,並結合第一個解決方案,可以得到一個不同的 15 個關鍵字長度的解決方案:
async function* foo() {
if (0);
else do return yield delete void await this instanceof typeof new class extends async function
() {} {}; while (0)
}
複製程式碼
哦耶!
更有趣的在這兒
雖然這樣做沒什麼意思,但賣弄知識卻很有趣。
但不用擔心,因為在下面的討論中 Bterlson 作了這樣的補充:
this
、null
和undefined
可以認為是關鍵字,即使它們在技術上不是關鍵字。這使得比賽更有趣(加上編輯們把它們標記成關鍵字,所以這麼說也行得通)
從技術層面講,this
實際上是一個關鍵字。但是,Bterlson 對 null
和 undefined
不是關鍵字的認定卻是正確的。
在餘下部分,我們可以看到 true
和 false
也被當作關鍵字使用。這就給我們帶來了一個問題:如果可以使用非關鍵字標記,那麼對於這個挑戰,哪些標記更合適?
null
、true
和 false
的共同點是它們都是隻包含字母的字面量(顯然,包含字元和數字的字面量是不允許的)。
由於可以使用 null 字元和 boolean 字元,我們可以輕鬆地復現出先前的序列,並構建 17 個單詞長度的序列:
async function* foo() {
if (0);
else do return yield await delete void typeof null instanceof this in new class extends async function () {} {}; while (0);
}
複製程式碼
那 undefined
呢?它實際上是一個識別符號。如果允許 ASI,那我們就可以使用任意識別符號去構造一個無限序列,但這就索然無味了,也失去了挑戰的樂趣。
a
b
c
// boooring
複製程式碼
我倒認為這項挑戰的意義在於僅使用類似關鍵字的標記完成挑戰(即使這些類似關鍵字的詞在技術層面不能算作規範的關鍵字)。
下面是一些看起來像關鍵字但實際上不是關鍵字的標記:
let x
for (foo of bar) {}
class { static foo() {} }
import {foo as bar} from 'baz'
{get foo() {}, set foo() {}}
複製程式碼
如果你不喜歡仔細研究程式語言諸多的規範,而且不能一眼看出哪些標記是關鍵字,哪些不是關鍵字,那麼下面的標記都可以當作是關鍵字:let
、of
、static
、as
、from
、get
、set
。它們看起來也確實像關鍵字。
我們可能認為不可以往上面的列表中新增 NaN
和 Infinity
之類的東西,是因為它們與 undefined
屬於同一個型別,都是識別符號(識別符號總是指向相同的值),也可能是由於只允許使用小寫字元。不管怎樣,我們將它們排除在外。我們也應該排除 atguments
,因為在語法規範中它沒有作為標記出現,因此它實際上只是一個 magic 變數,而不是關鍵字。
另一個我們需要排除是 new.target
,因為它中間有一個“.”。
一些標記例如 enum
和 public
是保留字,它們看起來非常像關鍵字,特別是如果你熟悉像 Java 這樣的語言。問題是,它們在語法中幾乎處處都會自動變成語法錯誤,所以即使我們允許使用它們,也不能真正地使用它們...
// the party poopers
let enum // SyntaxError
interface Bar {} // SyntaxError
package Baz; // SyntaxError
class {
private foo() {} // SyntaxError
}
複製程式碼
既然我們已經理清了規則,我們接下來能做什麼呢?
當然有很多啦
由於一貫的向後相容性問題,在某些情況下,許多“關鍵字” 充當...呃,不能稱它們為關鍵詞。我們之前說過濫用 ASI 和識別符號很無聊,但你知道嗎?在 Javascript 他們卻是有效的語法。
var undefined
typeof let
複製程式碼
這當然不是無聊的,而且非常有希望,所以以娛樂的名義,我們必須允許它。
最後還有一個小細節要談。雖然上面的程式碼片段很有趣,而且讓人眼花繚亂,但它有一個問題:它跨越了兩行。很不幸,但我們需要 ASI 將這兩個語句分開,所以我們無法將它們放在同一行。
或者這樣做:
輸入一個段落分隔符(\u2029
),如果正確呈現,它看起來如下:
什麼都看不見?這就對了!這是一個隱形變數。
現在,有了上面的知識儲備,我們可以提出自己的解決方案:
async function* foo() {
from: set: while (0) {
if (0)
throw as
else this
null
continue from
false
break set
true
var let
debugger
do return yield await delete void typeof get instanceof static in new class of extends async function undefined
() {} {}; while (0);
}
}
複製程式碼
你沒看錯,這就是在 Chrome 上解析和執行有效的 Javascript 程式。這可是在一行中有 32 個關鍵字的序列!
當然,並不是所有 32 個詞都是關鍵字,這可能是 ASI 有史以來最嚴重的濫用,但是,這仍然有挑戰意義。另外,我很開心,這才是最重要的!
那麼,你覺得呢?你能做一個更長的序列嗎?你能弄明白為什麼這在語法上是有效的嗎?這是作弊嗎?Gists [譯者注:原文釋出在 gist 上]是有史以來最被濫用的部落格平臺嗎?
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。