我们中庆祝圣诞节或光明节的人可能对 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 }
我知道很多人会提到
- 箭头函数有一行代码可以做到这一点,而且
- 我不喜欢上面模板字面量中的花括号
我喜欢这样做的原因是
- 一些封装可以提供清晰度,尤其是在逻辑方面,并且
- 花括号是一个更强的视觉信号,因为它们是更多的视觉噪音。函数足够重要,需要这种高级别的视觉状态,而模板字面量则不需要。
好的,现在让我们深入一步。如果我们总是在最后一行隐式返回呢?所以,现在我们可以这样做
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 对我的包容和校对本文。
有趣。我希望存在:
Array.prototype.last
,因为我不喜欢[list.length-1]
。好消息!有一个 第一阶段 的提案 https://github.com/keithamus/proposal-array-last
不错,感谢链接,Simeon!
我的天啊。非常感谢。我正在学习
理解
JS。^^我喜欢这种方法,但我不知道我是否真的喜欢任何具体的建议。但这整个目的都是为了促进讨论,对吧?所以这是我的想法 :)
在三元运算符中使用管道很有趣,但与现有语法冲突。在我看来,这还不够。最好添加一个语言特性(可能是模式匹配?)为表达式添加更简洁的 if-elseif 语法。
const foo = (x) => { ... }
比较笨拙,但我担心foo(x) { ... }
可能不会清楚地表明正在发生什么。不过,这是一个小问题,总的来说,我比较喜欢这个,仅供参考。感谢您撰写本文,这绝对是一次有趣的思维练习!
在我看来,隐式返回将是一个积极的改变,但我们需要将其与更符合人体工程学的返回未定义的方式(如标准的非返回函数)结合起来。
如果我们将其与另一个语法调整结合起来会怎么样。由于 JS 使用分号 (;) 作为语句终止符,如果解释器在连续的分号之间插入一个
undefined
语句会怎么样。例如,;;
将被解释为;undefined;
例如,一个标准函数
可以用 Sarah 提出的语法写成
我同意模板字面量很棒,但除此之外,我不同意大多数观点。例如隐式返回……您希望消除
return
这个词的必要性。但要求它在您想要一个void
函数时使用?这只是在转移“问题”。欢迎来到 CoffeeScript!
CoffeeScript 中一直困扰我的一件事是,使函数无效的笨拙方式
实际上,用返回值的函数替换
console.log
。嗯,我从来没有真正错过JS模板(将它们全部保存在非执行脚本标签中)。在组件内混合技术非常现代,但这并不是编写干净且易于管理代码的唯一方法。
此示例演示如何将模板与js代码分离(jQuery风格)。易于嵌入到几乎任何CMS中。易于使用svn、git等进行维护。
在该模式之上构建自己的抽象非常容易,而无需实现数十种(vue、react)或数百种(angular)新的语义。
听起来你已经准备好学习函数式编程了!尝试一种基于ML的语言。你会发现你正在寻找的很多东西都隐藏在那里。鉴于你对JS的喜爱,也许Elm是一个简单的方向……如果不是,那么也许是F#(个人最喜欢的)或Haskell(如果你敢的话!)。
你假设我还没有尝试过Elm等;)
如果你的三元运算符如此复杂,那么普通的if语法是否比这个新建议的三元运算符更简洁呢?
是的,我同意你的观点。我并不是唯一一个编写我维护的代码的人,但最近很多人都在这样写三元运算符。
这是三元运算符从一开始就是个坏主意的原因之一。
如果你真的想写一个if/else语句,那就直接写吧!
我个人会这样写
为
是的,这可能更好。
根据我的经验,CoffeeScript的隐式返回导致了许多非常难以追踪的错误。在一种有如此多副作用且不是严格函数式的语言中,我认为我们最好明确地说明我们打算返回什么。
有趣。看起来你创建了自己的CoffeeScript :)
我喜欢你的一些想法,尤其是隐式返回。我曾使用过带有隐式返回的语言,它真的很好用。我从未需要显式返回
undefined
。它很自然,就像我们使用do表达式
时会得到的一样。为了解决嵌套条件表达式(无论如何我都避免使用它们),我宁愿看到函数签名和函数重载中的模式匹配。所以不是这样
你得到
当然,在重载时
const
关键字看起来不太合适,但你明白我的意思:D顺便说一句,我们可能会得到模式匹配,只是不在函数签名中……但这仍然比嵌套条件表达式好得多。目前仅处于第0阶段。
是的!击个掌
怎么样自动柯里化像这样
以便柯里化行为像
就像Ramda.curry
我爱柯里化
我喜欢它,Mr Curry
我喜欢你关于如何简化语言的想法,一篇非常鼓舞人心的文章!当思考这个问题时,我还希望能够在声明变量时跳过
let
、const
和var
关键字(像Python一样)。例如:当键入
x = 1
时,它将被视为作用域变量,就像今天使用let
一样。如果今天这样做,我认为变量将被视为全局变量(var
),并且世界上每个代码检查工具和IDE都可能会崩溃。这正是我可以接受的那种简化。
不幸的是,三元运算符不能使用管道代替冒号,因为单个管道字符已经是“按位或”运算符。
(面向对象)设计模式,用于解决重复出现的问题。
以描述或模板格式(而不是静态的“完成”复制粘贴代码段),以便可以根据特定情况或特定环境定制每个模式以解决问题。
我喜欢简化的函数格式的想法,它还可以使代码更容易重构进出类等。我不喜欢它的地方是删除箭头语法单行语句。
当以这种方式使用时,当前语法更易于阅读。但是,如果箭头语法仅适用于自动返回值的单行表达式,那可能会很好。
这将允许我们做以下事情
https://gist.github.com/AnastasiaDunbar/b87aa100af309c3eba23a27f7ae0d617
模板字面量
我想继续使用
${}
而不是[]
,因为转义字符会很麻烦,而且Ruby使用#{}
,它类似于JavaScript,我认为使用两个字符来开始字符串插值感觉更好,即使你可能讨厌美元符号。三元运算符
对于使用过C语言的新手来说,使用
|
代替:
作为三元运算符会令人困惑,而且我看不出这样做有什么好处。箭头函数
这里有一个问题,那就是局部作用域
很棒的文章,喜欢对JS语法未来发展方向的分析。
箭头函数可能使代码更易于编写,但它们难以阅读。每当我看到=>时,我都会想到=。它需要一个不同的符号,一个不用作运算符的符号。