文章来源:https://www.tinyblog.dev/blog/2020-07-13-javascript-roro-pattern/
Javascript RORO 模式
一种编写更具可读性的函数的好方法
代码可读性是一件大事。开发人员花费大量时间阅读代码:其他人的代码、我们自己的代码、我们以前从未见过的代码等。以尽可能可读的方式编写代码可以帮助团队中的每个人节省大量时间。可读性有时会与性能有所折衷,但我尽量保持可读性。
我必须非常喜欢 Javascript 的一种模式是 RORO 模式,即接收对象、返回对象。该模式的要点如下:函数应该始终接受一个对象作为它们的参数,并且它们应该始终返回一个对象作为其结果。然后,我们将解构参数和返回值,以便以更有表现力的方式了解进出函数的内容。接收一个对象作为我编写的所有函数的标准是我在学习 Python 并获得 kwargs 经验后开始做的事情,我非常喜欢它,因为它使了解函数的内容变得如此容易。能够标记传递给函数的参数真是太好了,Javascript 中的 RORO 模式为我们提供了一些类似的功能。
考虑以下函数调用
const item = await getItemFromCollection(54391, 'shop');
这是我试图避免编写的函数类型。这个函数有一个足够描述性的名字,我们可以假设它会从一个集合中获取一个项目。但是,其余的信息是什么意思?我们可以尝试对其中的一些进行一些有根据的猜测;54391看起来最像一个id,shop大概就是一个系列的名字。不过,我们不能对其中任何一个持肯定态度,为了完全理解这个接口,我们必须在我们的代码库中找到函数声明。
async function getItemFromCollection(id, collectionName) {
好的,所以我们必须浏览代码库并找到该函数,但这需要一些时间。如果我们使用 RORO 模式编写这个函数,我们可以消除这样做的需要。
async function getItemFromCollection({ id, collectionName }) {
// do something
};
const item = await getItemFromCollection({
id: 54391,
collectionName: 'shop',
});
通过立即解构参数对象,我们在声明我们的函数时具有大部分相同的语法。然而,稍后当我们调用我们的函数时,我们现在有一种方法可以传递命名参数。仅仅通过阅读函数调用,我们就可以确切地知道不同的参数应该是什么,不再需要在函数的声明位置查找函数以获得上下文。争论的上下文现在是调用本身的一部分,我发现它更具可读性,并且必须减少搜索代码库/文档的时间。
我开始采用这种模式的一个重要原因是我对传入的布尔参数非常不屑。考虑:
someFunctionCall(false);
我根本不喜欢看到这样的功能。布尔值提供的信息非常少,我已经看到人们试图以各种方式纠正这一点。
const variableNameDescribingBooleansPurpose = false;
someFunctionCall(variableNameDescribingBooleansPurpose);
someFunctionCall(/* comment describing the booleans purpose*/ false)
最好的解决方案是传入一个对象并立即解构。将传递的内容的描述直接与函数调用本身联系起来,无需再做任何额外的事情来使您的代码可读;它只是可读的。
someFunctionCall({ booleanPurpose: false });
现在,这个模式确实有两个部分。到目前为止,我们已经接触到了 Receive an Object 部分,但仍然留下了 Return an Object。这与我们已经讨论过的类似;我们的函数将返回对象,我们将立即解构以获得我们想要的数据。这样做的好处在于,它为我们的函数提供了某些语言具有但 Javascript 本身不支持的功能:单个返回中的多个项目。
async function runProcess({ processName }) {
// run process on your server
// maybe you decide to cache the results of this process running
return { result, wasCached };
};
// destructuring off the result we can now have multiple items return from our function
const { result, wasCached } = await runProcess({ processName });
if (wasCached) {
// run another process
}
我个人得到的 Return 和 Object 的效用比 Receive an Object 要少得多。多个返回项非常好,但我发现我编写的大多数函数只关心一件事情。在这种情况下,当您可以像平常一样将其存储在变量中时,必须对返回值进行解构,这需要一些额外的劳动。它偶尔会派上用场,但我并不总是使用它。
我发现所有这些中最有用的部分是命名参数。我刚刚发现函数更容易阅读;特别是在处理多参数函数或接受布尔值的函数时。多个返回项目也很好,但在更小众的情况下发挥作用。归根结底,这种模式是为了让我们的 Javascript 功能更加灵活。在学习了 Python 和 Go 并看到这些语言为其功能所做的一些好事后,我开始采用这种编程风格。从其他来源汲取灵感是学习和提高的好方法!