JavaScript,我爱你,你完美无缺,现在该改变了

Avatar of Sarah Drasner
Sarah Drasner

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

我们中庆祝圣诞节或光明节的人可能对 12 月的兴奋记忆犹新。您还记得圣诞节前的几个月吗?那时您的想象力充满了各种想法,对“圣诞节想要什么”这个大问题的答案层出不穷。作为孩子,因为您没有成年人的责任,甚至不受现实的限制,愿望清单可以从“乐高积木”到“去月球旅行”(这在未来几年似乎更有可能实现)不等。

跳出既定的基础前提——我们所知道的某件事的局限性——可以是一项有益的心理练习。例如,我热爱 JavaScript,但如果像小时候的圣诞节一样,我可以决定它是什么呢?语法上的一些小调整不会改变我的生活,但会让它变得更好。让我们来看一看。

正如我的同事兼朋友 Brian Holt 所说:

拿出你的画笔!今天,我们来 bikeshedding(纠结于细枝末节)了!

模板字面量

首先,我应该说,模板字面量很可能是 ES6 中我最喜欢的东西。作为一名经常操作 SVG 路径字符串的人,从字符串连接到模板字面量的转变确实改变了我的生活。看看这个函数的返回值

function newWobble(rate, startX) {
  ...
  
  if (i % 2 === 0) {
    pathArr2[i] = pathArr2[i] + " Q " + in1 + " " + QRate;
  } else {
    pathArr2[i] = pathArr2[i] + " Q " + in2 + " " + QRate;
  }

  ...
  return "M" + pathArr2.join("") + " " + startX + " " + (inc * (rate*2) + rate);
}

改为

const newWobble = (rate, startX) => {
  ...
  
  if (i % 2 === 0) {
    pathArr2[i] = `${pathArr2[i]} Q ${in1} ${QRate}`;
  } else {
    pathArr2[i] = `${pathArr2[i]} Q ${in2} ${QRate}`;
  }

  ...
  return `M${pathArr2.join("")} ${startX} ${(inc * (rate*2) + rate)}`;
}

……这更容易阅读和使用。但这可以改进吗?当然可以!

当我们必须解析 ${x} 时,会产生一小部分认知负担,这主要是由于字符本身的性质。那么,如果模板字面量去除美元符号,改为使用方括号呢?而不是

return `M${pathArr2.join("")} ${startX} ${(inc * (rate*2) + rate)}`

……我们可以使用类似以下的内容

return `M[pathArr2.join("")] [startX] [(inc * (rate*2) + rate)]`

……这更加简洁。

三元运算符

三元运算符很有趣,因为近年来,它们没有改变,但我们变了。许多现代 JavaScript 大量使用三元运算符,这导致我重新审视它们目前的语法。

例如,像这样的一行代码

const func = function( .. ) {
  return condition1 ? value1 : value2
}

……并不难阅读和理解。但最近我一直在阅读很多这样的代码

const func = function( .. ) {
  return condition1 ? value1
       : condition2 ? value2
       : condition3 ? value3
       :              value4
}

这更难阅读,主要是因为冒号 : 根据您的代码编辑器和语法高亮设置而变得难以辨认。而且,如果有人没有正确格式化该代码呢?它很容易变成

const func = function( .. ) {
  return condition1 ? value1 : condition2 ? value2 : condition3 ? value3 : value4
}

……在这种情况下,冒号很难一眼就看出来。那么,如果我们使用更强的视觉指示符呢?

const func = function( .. ) {
  return condition1 ? value1 | condition2 ? value2 | condition3 ? value3 | value4
}

管道不会打断代码的流程,但仍然以一种不容易在行中迷失的方式进行分隔。

箭头函数

我要为此付出代价了,因为这是每个人最喜欢的,但箭头函数一直是我不喜欢的东西。不是因为它们没有用——恰恰相反。箭头函数很棒!但那个粗箭头在可读性方面总有些让我感到不爽的地方。我现在已经习惯了,但让我感到困扰的是,当我第一次学习它们时,我需要多花一两秒钟才能读懂它们。最终这个问题消失了,但让我们假设我们可以鱼与熊掌兼得。

我绝对不是建议我们仍然使用 function 这个词。事实上,我希望箭头函数天生不是匿名的,因为

const foo = (y) => { 
  const x
  return x + y
}

……不如

const foo(y) => {
  const x
  return x + y
}

在我理想的世界里,我们会去掉 function 和箭头,以便我们可以得到一些更像方法的东西

foo(y) {
  const x
  return x + y
}

匿名函数可以简单地写成

(y) {
  const x
  return x + y
}

甚至是一行代码

(y) { y += 1 }

我知道很多人会提到

  1. 箭头函数有一行代码可以做到这一点,而且
  2. 我不喜欢上面模板字面量中的花括号

我喜欢这样做的原因是

  1. 一些封装可以提供清晰度,尤其是在逻辑方面,并且
  2. 花括号是一个更强的视觉信号,因为它们是更多的视觉噪音。函数足够重要,需要这种高级别的视觉状态,而模板字面量则不需要。

好的,现在让我们深入一步。如果我们总是在最后一行隐式返回呢?所以,现在我们可以这样做

foo(y) {
  const x
  x + y
}

或者……

(y) {
  const x
  x + y
}

如果我们不想返回,我们仍然可以说

foo(y) {
  const x
  x + y
  return
}

或者,更好的是,使用一个特殊字符

foo(y) {
  const x
  x + y
  ^
}

这样,任何时候你想返回最后一行以外的不同行,你都可以使用 return,它会像往常一样工作

foo(y) {
  const x
  return x + y
  const z
}

那将是一个多么美好的世界啊,对吧?

现在怎么办?

人们发明新的语言并重写编译器,仅仅是因为他们对语言应该如何发展,甚至应该如何编写有强烈的意见。我最喜欢的例子包括 空格语言,这是一种由所有制表符和空格组成的编程语言,以及 Malbolge,它专门设计成无法用它进行编程。(如果你认为我写这篇文章很无聊,那我就没法比得上写出 Malbolge 的那个人了。)在文章中

事实上,作者本人从未编写过任何 Malbolge 程序

对于那些更认真地希望开发自己的编程语言的人,有一些资源可供您使用,学习起来非常有趣。

我意识到 JavaScript 无法进行这些更改是有原因的。本文并非旨在成为 TC39 的提案,而仅仅是一次思维练习。重新想象你认为不可改变的事物,检查你对基本前提的假设,这很有趣。必要性可能是发明之母,但游戏是其父亲。

非常感谢 Brian Holt 和 Kent C. Dodds 对我的包容和校对本文。