[译] 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前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索