javascript - 如何扩充现有函数,使其懒惰地解开其参数?
问题描述
我有一堆常规的实用功能。我想将这些函数转换为接受包含在函数中的参数的函数(以在使用值时引入副作用)。
// Some utility function:
const pick = (takeLeft, left, right) =>
takeLeft ? left : right;
// Some wrapper with a side-effect
const Watched = x => () => {
console.log(`Value ${x} is used`);
return x;
};
// I want this to log:
// Value true is used
// Value L is used
const myPick = runWithWatchedValues(
pick,
Watched(true), Watched("L"), Watched("R")
);
我正在寻求帮助实施runWithWatchedValues
,或者有人向我解释为什么它不能完成。
尝试
在调用内部函数之前解包值的问题:
// An incorrect attempt: (also logs "R")
const runWithWatchableValues = (f, ...args) =>
f(...args.map(w => w()));
我测试了使用apply
和一些特殊的 getter 调用该函数是否可以工作,但事实证明这完全一样。
// Another incorrect attempt: (also logs "R")
const runWithWatchableValues = (f, ...watched) => {
const args = watched.reduce(
(acc, get, i) => Object.defineProperty(acc, i, { get }),
[]
);
return f.apply(null, args);
};
我目前的解决方案是手动重写实用程序函数。IE:
const pick = (takeLeft, left, right) =>
takeLeft ? left : right;
const pickW = (takeLeft, left, right) =>
takeLeft() ? left() : right();
// Correctly logs true and L
pickW(Watched(true), Watched("L"), Watched("R"));
当有像 ramda 或 lodash 这样有据可查且维护良好的库时,我宁愿不维护自己的实用函数库……</p>
问题
我开始觉得我想要的只是语言无法做到的……但我希望我错了!
- 理论上是否可以编写
runWithWatchableValues
并获得所需的结果?- 如果是,如何?
- 如果没有,是否有另一种自动化方式(Babel/构建步骤?)您可以考虑避免手动重写
pick
以使用包装值?
“这是一个 x/y 问题!”</h2>
可能是这样,但我想保持简单。这是我真正在做的事情(使用 knockout.js):
const pick = (takeLeft, left, right) =>
takeLeft ? left : right;
const takeLeft = ko.observable(true);
const left = ko.observable("L");
const right = ko.observable("R");
// BROKEN: The easy, but wrong implementation:
const myPick = ko.pureComputed(
() => pick(takeLeft(), left(), right())
);
console.log(
"Naive approach:",
myPick(), // Right: "L"
myPick.getDependenciesCount() // Wrong: 3
);
// The dependency on `right` will mean that updating
// it will cause myPick to re-evaluate, even though we
// already know its return value won't change.
// FIXED: The manual fix:
const pickObs = (takeLeft, left, right) =>
takeLeft() ? left() : right();
const myCorrectPick = ko.pureComputed(
() => pickObs(takeLeft, left, right)
);
console.log(
"With manual rewrite:",
myCorrectPick(), // Right: "L"
myCorrectPick.getDependenciesCount() // Right: 2
);
// Changing `right` doesn't do anything. Only once `takeLeft`
// is set to `false`, a dependency on `right` will be created
// (and the dependency on `left` will be removed).
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
解决方案
理论上是否可以编写
runWithWatchableValues
并获得所需的结果?
不,参数不会在 JavaScript 中延迟传递。在将值传递给包装函数之前,您需要严格评估函数,这就是您要避免的。
是否有另一种自动化方式(Babel/构建步骤?)您可以考虑避免手动重写 pick 以使用包装值?
当然,您可以编写自己的编译器来执行此操作(看起来相对容易),但我怀疑是否存在执行此操作的现有 babel 插件。惰性求值通常是没有用的,大多数函数在任何情况下都会使用它们的所有参数。
推荐阅读
- java - Maven Build 没有创建可执行的 jar 文件
- amazon-web-services - 在 Redis ReJSON 的部署中共享 PV 不起作用
- python - 无法找到适用于 Python 的 IBM NLU 最新语法
- javascript - 通过多个组件传递数据类
- iis - 如何在没有代码的情况下在 IIS 中查看会话和会话信息
- node.js - writeFileSync only write half of data
- azure-devops - 天蓝色管道拉依赖项目
- java - I am trying to get gestures in here mobile sdk but didn't understand what to pass to gestures method? How to solve this
- android - 在视频视图中使用搜索栏时如何举杯?
- bash - 尝试查找包含标识符的文件,然后将它们移动到终端中的新目录