aku*_*kuz 2 javascript functional-programming underscore.js
根据我对函数式编程的理解,你应该能够链接多个函数,然后通过输入一次数据来执行整个链.
换句话说,当我执行以下操作(伪代码)时:
list = [1, 2, 3];
sum_squares = list
.map(function(item) { return item * item; })
.reduce(function(total, item) { return total + item; }, 0);
Run Code Online (Sandbox Code Playgroud)
我希望列表将被遍历一次,当每个值都被平方,然后一切都将被加起来(因此,reduce操作将根据需要调用map操作).
但是,当我查看Underscore.js的源代码时,我发现所有"函数式编程"函数实际上都会生成中间集合,例如:
// Return the results of applying the iteratee to each element.
_.map = _.collect = function(obj, iteratee, context) {
iteratee = cb(iteratee, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
results = Array(length);
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
Run Code Online (Sandbox Code Playgroud)
所以问题是,如标题所述,我们在使用Underscore.js时自欺欺人地进行函数式编程?
我们实际上做的是使程序看起来像函数式编程,而实际上它实际上并不是函数式编程.想象一下,我在长度为N的列表上构建了一长串K filter()函数,然后在Underscore.js中,我的计算复杂度将是O(K*N)而不是函数编程中预期的O(N).
PS我在JavaScript中听到了很多关于函数式编程的知识,我期待看到一些函数,生成器,绑定......我错过了什么?
Underscore.js功能性编程是假的吗?
不,Underscore确实有很多有用的功能辅助功能.但是,是的,他们做错了.你可能想要看一下Ramda.
我希望列表将被遍历一次
是的,list只会被遍历一次.它不会被改变,它不会被保存在内存中(如果你没有变量引用它).什么reduce穿越是一个不同的列表,所生产的一个map.
所有功能实际上都产生了中间集合
是的,这是用JavaScript这样的语言实现这一点的最简单方法.许多人在map调用之前依赖于执行所有回调reduce,因为它们使用副作用.JS不强制执行纯函数,库作者不想让人混淆.
请注意,即使在像Haskell这样的纯语言中,也会构建一个中间结构1,尽管它会被懒散地使用,因此它永远不会被分配为一个整体.
有些库可以用严格的语言实现这种优化,其中传感器的概念可以从Clojure中获知.JS中的例子是换能器,换能器-js,换能器.js或腋下.下划线和Ramda一直在寻找到他们2了.
我期待看到一些发电机
是的,可以懒散地消耗的生成器/迭代器是另一种选择.你想看看Lazy.js,highland或immutable-js.
[1]:嗯,不是真的 - 这是一个太容易的优化
[2]:https://github.com/jashkenas/underscore/issues/1896,https://github.com/ramda/ramda/pull/865
| 归档时间: |
|
| 查看次数: |
637 次 |
| 最近记录: |