继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

JavaScript纯与净:只用对象和函数写作

HUWWW
关注TA
已关注
手记 285
粉丝 37
获赞 133

最棒的 JavaScript 是简单明了,没有被这些所谓的垃圾特性,比如类、this、继承和装饰器所沾染。

TLDR; (摘要)

JavaScript 是一种非常强大的编程语言,具有多样化的语言特性。说实话,这些年来,大多数特性简直没用,反而限制了工程师写出高质量代码的能力。我只用对象和函数,感觉好多了。

关于JavaScript的问题

Javascript 是非常棒的语言。关于 Javascript 最令人惊叹的事情是它自发明以来的巨大进步。大多数语言的发展路径是被创造、淘汰直至消亡。当弱语言不够强大时,它们会被新的语言超越,最终消失。

JavaScript 就是那个不按常理出牌的语言。

尽管JavaScript很薄弱,因为它运行着Web,所以它不能被废弃。相反,新的特性被添加、拼凑,并用各种方式绑在外部。

今天我们又熟悉又讨厌又爱的 JavaScript 是一个特性的贫民窟,这些特性堆叠在一个从一开始就备受质疑的核心引擎之上的。

社区遇到的问题

真正的問題不是JavaScript,而是工程師被教导如何去思考和使用JavaScript的方式。他們被教导每个语言特性都有其独到之处和用途,并且都有其适用的场合和时机,因此,他们应该学习并尽可能地应用每一个特性。

不是真的。

我们以原型继承为例。它既奇怪又丑陋,它在现代编程语言中完全没有地位。仅仅因为这种语言里有它,并不意味着我们应该接受它。

解决办法

我反对所有那些肮脏的特性。我直接拒绝。尤其重要的是,我不会使用类、this关键字、装饰器,也不会依赖任何形式的继承。我的Javascript代码纯粹由对象和函数构成。

我不上课

类其实就是一个被赋予了状态的对象,真的,就这么简单!

以下两个代码片段在功能或作用上是一致的。两者之间的唯一区别在于,类实例化解析器需要 new 关键字,而常量解析器则不需要。

那我为什么要用类呢?如果你在想继承,可以看看下面这段代码。

任何类能做到的事,我用对象和函数也能做到,而且这并不难做。

我不做装饰这行

我其实很喜欢装饰器这个概念。遗憾的是,那个 Javascript 委员会在决定这种格式的那天晚上,喝醉了不该喝的酒,已经酩酊大醉。

简单来说,装饰器是一个函数,它装饰另一个函数,在被装饰的函数执行前后做一些可选的处理。

要做到这一点,Javascript 创建了一种你需要学习的语法。我更倾向于 Python 的方式。在 Python 中,装饰器 (decorator) 是一个接受函数作为参数并返回一个函数的函数。

这是我用 Javascript 实现的:

不带 @ 的 JS 装饰器

在这个例子中,我们用 uppercaseemphasize 装饰器装饰了 speak 函数,从而创建了 scream 函数。实际上,我们并没有在装饰,而是在进行组合。这并不是错误,而是特性之一。无论怎样,我们还是达到了装饰的基本目的。

为什麼呢?

有几条原因让我只使用对象和函数。简而言之,这样做可以使我的代码更简洁、易读、运行更快,并使代码更“好”。我特别喜欢这种“更好”的感觉。

类倾向于累积状态

这并不是一条严格的规定,而是在我的职业生涯中观察到的一种趋势。我个人强烈偏好确定性的代码,以及在可能的情况下,纯函数。如果你能自律,你可以通过类来达成这些目标。然而,这似乎总是不能持久。即使我自律,也不太可能接下来的10个工程师都会跟我有同样的想法。

随时间推移,类会慢慢积累更多的属性,并添加更多依赖这些属性的方法。当类变得难以控制时,这些属性在任何时刻的正确性变得对方法至关重要。也就是我们所说的“状态噩梦”。

这种有状态的复杂性是我希望 揭示出来 的。将状态揭示出来是函数式编程的一个原则。有状态的代码和可能会产生副作用的代码应该上升到软件的最高层,这一层之下的所有代码都应该是严格确定性的,并尽可能做到纯粹。

不可变的对象实例,具有模块作用域内的确定性函数。

通过对象,我可以在模块级编写确定性函数,并从对象实例调用它们,仅传递必要的信息。这强制手动传递状态给函数,并且希望这样,使工程师在添加内容时更加谨慎。这会促使工程师在添加内容时更加小心。

你可以用类来做到这一点,但已经有三十多年的先例表明不应该这样去做。当其他人查阅你的代码并发现一个类时,他们会不假思索地增加类的状态。

类更难测试了

这一点和前面提到的一点紧密相连。一个类的状态越多,它就越难进行测试。当我们通过将该类变为不可变对象来移除其状态,然后将复杂的功能移至模块作用域内,使其可以独立进行测试时,我们大大降低了测试的复杂性。

我是单元测试代码覆盖率的忠实粉丝。因为一些痛苦的经历,我可以告诉你,状态类的代码覆盖率 几乎毫无意义。 ,另一方面,如果我的类是不可变的对象,模块作用域的函数都是确定性的,并且我已经用单元测试覆盖了所有确定性函数,这样我可以确定逻辑已经被完全覆盖。

摩托车分类

我们的摩托车类别有些荒诞——大家都认为红色的摩托车跑得最快——但它确实展示了现实中的一个例子,其中结果是由政府决定的。

在编写测试代码时,可能不会意识到,例如颜色,其实会影响速度。

一个不可变的摩托车对象

在函数和对象版本里,为getSpeed函数编写测试会让开发者注意到颜色这个必需的参数会影响结果。

对象减轻认知负担

作为一个人,为了理解一个类中的方法,我必须把所有相关状态装在我的脑子里,然后思考运行时的行为。这通常意味着我会在方法中寻找像 thisself 这样的关键字来识别依赖的状态,看看它们是什么。

这类函数通过参数来确定依赖关系,通常来说,这使得理解和推理它们变得更加容易。

装饰器永远绑定到函数上

当我使用 Javascript 中的 @decorator 特性时,我会将装饰器函数永久绑定到被装饰的函数上。这样我就不能单独进行该函数的单元测试了。

让我们来看一个使用 speak/scream 的装饰器示例的版本。这个示例已经转换为使用 @decorator 特性。

正在工作的装饰者

我无法不运行装饰器就测试speak方法。作为一个注重单元测试质量的人,这对我来说完全无法接受。

装饰器需要较为晦涩的格式知识

请看以下代码片段,我们的装饰器函数,并告诉我:目标是什么?名称是什么?描述符又是什么?

强调装饰

唉,JavaScript 用复杂的格式扭曲了一个真正优雅的模式。装饰器的定义简洁且优美——一个函数,它接受并返回一个函数。

装饰器要求这个

就像我们在两个装饰器中看到的那样,它们需要使用 applythis 来正确设置被装饰方法的运行环境,其中 applythis 是关键的编程关键字用来设置上下文。

如果你能和我一起稍微打开心扉一会儿,我想和你们分享一下我对这的看法……20年前这是一个错误,今天它依然是个错误。JavaScript,请不要再围绕它构建语言特性,工程师们,请不要继续围绕它编写代码。

顺便提一下,如果我在面试你,问你解释一下javascript中的this关键字,正确的回答应该是“我不是很清楚,我不使用那个老古董玩意儿,它只会无谓地增加代码的复杂度而已。”

我是Ray,我是Vessel的联合创始人工程师,我创建了Radash、ACP设计模式和Exobase库。我并不想要你们的钱,我只是想在一个不那么糟糕的代码库中工作。所以请关注我、评论和互动,让我们一起做出更好的实践。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP