我想知道是否有一种简洁或特定的方式来访问JavaScript中FP链中间的值。示例:
const somestuff = [true, true, false];
let filteredCount = 0;
somestuff.filter((val) => val)
.forEach((val) => console.log(val));
上面,我想将filteredCount
设置为filter
函数返回的数组的长度。最直接的方式是:
const somestuff = [true, true, false];
const filteredStuff = somestuff.filter((val) => val);
let filteredCount = filteredStuff.length;
filteredStuff.forEach((val) => console.log(val));
这当然有效,但它打破了我们的FP链并引入了一个额外的保持变量。我想知道是否存在访问链中间值的约定。像.once()
这样运行一次并隐式返回传入的值,但不存在类似的东西。
答案 0 :(得分:1)
没有像这样的Array.prototype方法的原因是它有副作用。这是函数式编程中特别避免的。
但是,如果您不关心编写“纯函数”,甚至是函数范例,您可以将副作用放在回调函数中,或者在Array原型中编写函数。
即。
Array.prototype.once = function(callback) {
callback(this)
return this
}
您还有其他hacky选项,如其他答案
答案 1 :(得分:1)
为了进行调试,我经常使用名为tap
的函数临时将一个副作用(如console.log
)添加到函数中:
const tap = f => x => (f(x), x);
此函数返回传递的任何内容,但不会在使用该值调用另一个函数之前返回。例如:
const tap = f => x => (f(x), x);
const tapLog = tap(console.log);
const x = tapLog(10);
console.log("x is", x);

您的代码段基本上是这样做的:
length
属性如果使用pipe
或compose
构建此功能,则可以"注入"中间的console.log
不会中断数据流:
const countTrues = pipe(
filter(isTrue),
prop("length")
);
const countTruesWithLog = pipe(
filter(isTrue),
tap(console.log),
prop("length")
);
在一个片段中:
// Utils
const isTrue = x => x === true;
const prop = k => obj => obj[k];
const tap = f => x => (f(x), x);
const filter = f => xs => xs.filter(f);
const pipe = (...fns) => x => fns.reduce((res, f) => f(res), x);
// Logic:
// Filter an array using the isTrue function
// and return the length of the result
const countTrues = pipe(
filter(isTrue),
prop("length")
);
// Create a filter with a console.log side-effect
// and return the length of the result
const countTruesWithLog = pipe(
filter(isTrue),
tap(console.log),
prop("length")
);
// App:
const somestuff = [true, true, false];
console.log("pure:");
const countA = countTrues(somestuff)
console.log(countA);
console.log("with log:")
const countB = countTruesWithLog(somestuff);
console.log(countB);

答案 2 :(得分:0)
默认情况下,我认为没有类似的东西。你可以做的是扩展Array
,但我并不是真的喜欢扩展框架类(例如与其他once
实现的冲突)。在这种情况下,你最终得到:
Array.prototype.once = function once(func) {
func(this);
return this;
}
被称为:
var filteredStuff = somestuff
.filter((val) => val)
.once(function(array) {
console.log(array.length);
})
.forEach((val) => console.log(val));
另一方面,您可以尝试使用默认功能。其中一个可以一次访问所有项目的功能是reduce
。定义一个函数once
,它将调用它的第一个参数一次(:)
),你最终得到的结果如下:
function once(func) {
return function(accumulator, currentValue, currentIndex, array) {
if(currentIndex === 1) {
func(array);
}
return array;
}
}
你可以这样打电话:
var filteredStuff = somestuff
.filter((val) => val)
.reduce(once(function(array) {
console.log(array.length);
}), [0])
.forEach((val) => console.log(val));
注意丑陋的[0]
以确保once
至少调用一次传递的函数(包括空数组)。
这两种解决方案都不是很整洁,但鉴于标准,这是我能想到的最好的解决方案。