[譯] Javascript 中最長的關鍵字序列長什麼樣子?

最近有幾個關於使用 Javascript 編寫最長關鍵字序列的挑戰。前端

但問題是:android

  • 這些解決方案使用了非關鍵字標記(null、true、false 其實是字面量,而不是關鍵字)
  • 其中一個解決方案有些說不通

讓咱們試試能不能作的更好。ios

(可是咱們首先要回顧一些基礎規則)git

規則

  1. 代碼必須能做爲有效的 Javascript 進行解析和運行。不能忽略 early errors
  2. 只容許使用關鍵字
  3. 除小寫字母外,其它惟一容許的字符是空格
  4. 不能在序列中重複使用一個關鍵字
  5. 您能夠根據須要添加儘量多的前同步碼和後同步碼

額外挑戰

  1. 關鍵字之間容許換行
  2. 容許使用相似關鍵字的標記

進入正題

@arjunb_msft 提出的最長 15 個關鍵字的程序github

function *f() {
  if (1);
  else do return yield delete true instanceof typeof void new class extends false in this {}; while (1)
}
複製代碼

不幸的是,他的方法裏使用了保留字 truefalse,而二者實際上不是關鍵字。在 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,這也不是一個關鍵字。async

雖然有些賣弄,若是咱們從第二個解決方案中剔除 null,並結合第一個解決方案,能夠獲得一個不一樣的 15 個關鍵字長度的解決方案:編程語言

async function* foo() {
  if (0);
  else do return yield delete void await this instanceof typeof new class extends async function () {} {}; while (0)
}
複製代碼

哦耶!oop

更有趣的在這兒

雖然這樣作沒什麼意思,但賣弄知識卻頗有趣。

但不用擔憂,由於在下面的討論中 Bterlson 做了這樣的補充:

thisnullundefined 能夠認爲是關鍵字,即便它們在技術上不是關鍵字。這使得比賽更有趣(加上編輯們把它們標記成關鍵字,因此這麼說也行得通)

從技術層面講,this 其實是一個關鍵字。可是,Bterlson 對 nullundefined 不是關鍵字的認定倒是正確的。

在餘下部分,咱們能夠看到 truefalse 也被看成關鍵字使用。這就給咱們帶來了一個問題:若是可使用非關鍵字標記,那麼對於這個挑戰,哪些標記更合適?

nulltruefalse 的共同點是它們都是隻包含字母的字面量(顯然,包含字符和數字的字面量是不容許的)。

因爲可使用 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() {}}
複製代碼

若是你不喜歡仔細研究編程語言諸多的規範,並且不能一眼看出哪些標記是關鍵字,哪些不是關鍵字,那麼下面的標記均可以看成是關鍵字:letofstaticasfromgetset。它們看起來也確實像關鍵字。

咱們可能認爲不能夠往上面的列表中添加 NaNInfinity 之類的東西,是由於它們與 undefined 屬於同一個類型,都是標識符(標識符老是指向相同的值),也多是因爲只容許使用小寫字符。無論怎樣,咱們將它們排除在外。咱們也應該排除 atguments,由於在語法規範中它沒有做爲標記出現,所以它實際上只是一個 magic 變量,而不是關鍵字。

另外一個咱們須要排除是 new.target,由於它中間有一個「.」。

一些標記例如 enumpublic 是保留字,它們看起來很是像關鍵字,特別是若是你熟悉像 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 aselse thisnullcontinue fromfalsebreak set
 truevar letdebuggerdo 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 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索