搜索词
pure
isolated
functional
testing
functions
建议
我希望能够Assert一个函数是 isolated
,这被我定义为 "仅对作为输入传入的参数起作用"。孤立的函数在重构过程中更容易提取,并且可以与代码库的其他部分隔离进行测试,从而打开了像 doctests 这样的东西的可能性。
将继承的作用域应用于参数的函数不能是 isolated
。例如,如果你在使用 jQuery,你希望将 $
作为参数传递给你的孤立函数,即使它在全局范围内可用。
注意:声称一个函数是 isolated
与声称它是 pure
不是一回事。乍一看它们似乎是同义词,但我不认为在 JavaScript 中有可能实现 pure
函数,因为你无法控制调用方法等操作时产生的副作用等。传递 $
并对其进行操作是定义上的 非纯函数,但我们仍然可以将其视为孤立的! :)
如果一个函数被注解为 isolated
,那么如果它试图访问一个不是其参数之一的值,就会抛出编译错误。
用例
大胜利:更简单的重构
孤立的函数可以被移到任何源文件中,而不用担心改变其所在范围会破坏其行为。它携带自己的作用域,无论它身在何处。这也为代码如何占据文件系统提供了有趣和新颖的方法。我正在想象类似 Eve 编辑器的东西,其中“文件”是抽象概念,可能在未来不再像过去那样有用。
更大的胜利:测试
如果一个函数不依赖于外部作用域,那么对其进行测试就变得轻而易举 - 可以探索函数行为的每个部分。这不仅使函数在立即情况下更容易测试(简化模拟、隔离等),而且还为将来像 doctests 这样的事物打开了大门。(参见 Elixir 的 doctests 以了解我的意思)
示例
将孤立视为较严格的纯度。由于这是 JavaScript,我们无法控制当我们例如在一个参数上调用方法时会发生什么。运行时的可预测性足够高,以至于在没有添加显著的运行时破坏约束的情况下无法保证纯度。
然而,我们可以做的是检查我们的函数是否只对输入起作用。
/*
* @isolated
*/
function sum(x, y) { return x + y } // this works
/*
* @isolated
*/
function addX(value) { return value + x } // this throws a compiler error
this
任何显式地在 this
上的东西都算作一个输入参数,因为你可以随时调用/应用/绑定来调用它并传递一个 this
值。如果使用原型,这会使得重构变得复杂,因为你需要获取所有对该函数的引用,而不仅仅是定义,但对我来说仍然是可行且有用的?
这允许我们在对象和示例上拥有看似矛盾的 isolated
方法,我想。这里可能还有一些我没有考虑到的复杂性?
/*
* @isolated
*/
function updateModel(delta) {
this.model.patch(delta)
}
// and elsewhere
updateThisModel = updateModel.bind(model)
现有代码
由于这是一个选择性的Assert,因此不会对现有的代码库产生影响。此外,由于目标是在违反孤立时抛出编译错误,因此在代码库中有一个积极采用的途径。许多核心行为应该已经相当孤立了,能够做出这样的Assert将会给代码库带来很多新的稳定性。
/*
* @isolated
*/
function myReducer(accumulator, value) { return accumulator.push(value * 2) }
纯洁(及其明显的缺失)
让我们看看以下这个孤立的函数,它只是做一些 JQuery 的小把戏。我们可以Assert这个函数是 isolated
,因为 $
、 selector
和 value
都是作为参数传递进来的。但是这段代码不是 pure
,因为像这样调用 jQuery 有副作用。
尽管如此,我们仍然受益于孤立的好处,因为现在我们知道我们可以测试这个函数,而要做的就是模拟 $
。
/*
* @isolated
*/
function setValue($, selector, value) { $(selector).value(value) }
8条答案
按热度按时间3lxsmp7m1#
这听起来像是#17818 / #7770的重复。
lsmepo6l2#
我认为这是一个足够不同的问题,纯函数在这里有不同的含义(无副作用)。这个问题是关于提供一种声明该函数无法访问外部作用域的方法。
ha5z0ras3#
是的,我明确不追求函数纯度 - 这对我来说是一个非常复杂和困难的问题,可能在JS运行时根本无法解决。
这是关于编译时检查以确保函数的作用域与其环境隔离。
z5btuh9x4#
有人对此有任何进一步的想法吗?拒绝是可以的,但我想确保这一点很清楚,这不是纯函数的重复,
isolated
直接谈到了JavaScript/TypeScript上下文中函数纯度的问题。rslzwgfq5#
如果有一个术语可以描述一类功能,它既不是 pure ,也不是 closure ,那么或许可以将这个术语放入标题中以帮助消除歧义。
whitzsjs6#
实际上,如果有这样的关键字就好了。目前我正在使用Web Worker,这对我来说可以节省很多工作:(
请看这个例子:
main.ts
worker.js
这只能在孤立函数中工作,而且由于现在没有办法说某个函数是孤立的——我不得不重新整理我想以这种方式使用的函数,这让我很头疼。
csga3l587#
是的,这是一个很好的用例。有很多情况,特别是在进行并行或"线程"式编程时,拥有确保没有隐式作用域依赖的能力将非常有帮助!
nafvub8i8#
我今天在开发一个React应用时找到了这个功能的用例。我想确保在一个组件中定义的匿名函数只对其参数进行操作,而不会在外部作用域中的任何变量上闭包:
我认为隔离函数类似于C#中的静态局部函数,它们“不能捕获局部变量或示例状态”。
对于这个功能的一个实用补充是指定应该闭包的变量。没有例外可能会太限制了。例如,像lodash这样的实用程序包在使用某种类型的例外时会变得很难使用: