Javascript 如何使用Ramda.js更好地实现这一点
所以我有一个div列表:Javascript 如何使用Ramda.js更好地实现这一点,javascript,functional-programming,ramda.js,Javascript,Functional Programming,Ramda.js,所以我有一个div列表:list 我想要列表的一个子集,用.fade类删除div。 还可以使用.selected类从div中获取列表 所以使用R.takeWhile和R.dropWhile 然后我想映射这个新列表,并在该列表的子集上添加一个.active类,使用R.take和R.forEach或R.map 比如: var takeFromSelected = R.dropWhile(function(item){!$(item).hasClass('selected')}; var remov
list
我想要列表的一个子集,用.fade
类删除div。
还可以使用.selected
类从div中获取列表
所以使用R.takeWhile
和R.dropWhile
然后我想映射这个新列表,并在该列表的子集上添加一个.active
类,使用R.take
和R.forEach
或R.map
比如:
var takeFromSelected = R.dropWhile(function(item){!$(item).hasClass('selected')};
var removeFadeItems = R.takeWhile(function(item){!$(item).hasClass('fade')});
var addActiveClass = function(x){ $(x).addClass('.active')};
var processList = R.pipe(R.map(addActiveClass), removeFadeItems, takeFromSelected);
processList(list);
我对FP的东西真的很陌生,我正努力掌握它
任何见解都将受到极大的赞赏!!谢谢!:)
更新
为了将来参考,我做了以下工作:
@addActiveClass = (x)->
$(x).addClass('active')
return
@takeFromSelected = R.dropWhile((item)-> !$(item).hasClass('selected'))
@removeFadeItems = R.takeWhile((item)-> !$(item).hasClass('fade'))
@addWeekView = R.compose(addActiveClass, removeFadeItems, takeFromSelected)
我想你问这个问题是因为你得到了一个意想不到的结果 一般来说,addActiveClass函数引入了一个副作用——它修改了DOM。这没有错,但从FP的角度来看,你最好在IO单子中隔离这种效应 函数takeFromSelected和removeFadeItems使用谓词函数(函数(项){!$(项)…};);决定要放下和拿走什么。谓词函数需要返回true或false。在你的情况下,他们不会退回任何东西。解决方法是在
前面添加return
$(项目)
具有副作用的函数addActiveClass没有返回值。这会中断管道
,因为下一个函数removeFadeItems
不会显示任何内容。只需使addActiveClass
返回$(项目)
我还没有测试它,但是如果您添加三个return
s,它可能会工作
祝你好运
更新:因为
addActiveClass
返回一个jQuery对象并将其传递给removeFadeItems
,所以您不需要再次将项目包装在$()中。根据您的描述,听起来您想使用多于或
takeWhile
保留数组的值,直到谓词第一次失败:
> R.takeWhile(R.isEmpty, [[], [], [1, 2, 3], [], [1, 3]])
[ [], [] ]
> R.dropWhile(R.isEmpty, [[], [], [1, 2, 3], [], [1, 3]])
[ [ 1, 2, 3 ], [], [ 1, 3 ] ]
dropWhile
删除数组的值,直到谓词第一次失败:
> R.takeWhile(R.isEmpty, [[], [], [1, 2, 3], [], [1, 3]])
[ [], [] ]
> R.dropWhile(R.isEmpty, [[], [], [1, 2, 3], [], [1, 3]])
[ [ 1, 2, 3 ], [], [ 1, 3 ] ]
filter
删除所有不通过谓词的值
> R.filter(R.isEmpty, [[], [], [1, 2, 3], [], [1, 3]])
[ [], [], [] ]
在您的情况下,您需要以下内容:
var removeFadeItems = R.filter(function(x) {
return !$(x).hasClass('fade');
});
var takeFromSelected = R.filter(function(x) {
return $(x).hasClass('selected');
});
此外,正如@donut所说,您还需要返回一个值。然而,你和我的关系有点不好。因为它会改变值(这是一种副作用),所以使用map
有点用词不当。你最好使用,因为它是为副作用的东西:
var addActiveClass = function(x) {
$(x).addClass('active');
};
因此,你最终会:
var processList = R.pipe(
R.forEach(addActiveClass),
takeFromSelected,
removeFadeItems
);
processList(list);
重构
现在,由于您的一些函数是引用透明的(它们不会改变事物),您可以将其重构为更清晰、更可组合、更高效的函数
首先要注意的是,您正在每个函数中重写div。$
是一个很好的函数,可以用来包装东西一次。让我们从这个开始
var processList = R.pipe(
R.map($),
...
现在,允许您对对象调用函数。我们想在参数为active
的jquery包装对象上调用addClass
。让我们为其创建一个函数:
var addActive = R.invoker(1, 'addClass', 'active');
我们可以将其添加到管道中
var processList = R.pipe(
R.map($),
R.forEach(addActive),
...
var processList = R.pipe(
R.map($),
R.forEach(addActive),
R.filter(notFaded),
R.filter(selecteded)
);
过滤器与我们在addActive
中所做的类似,让我们先通过分离谓词来重构这些过滤器:
var faded = R.invoker(1, 'hasClass', 'fade');
var notFaded = R.not(faded);
var selecteded = R.invoker(1, 'hasClass', 'selected');
这里最棒的事情是ramda函数的可组合性,它允许我们说R.not(flated)
,而且一切都可以在不考虑它的情况下工作
因此,让我们将其添加到管道中
var processList = R.pipe(
R.map($),
R.forEach(addActive),
...
var processList = R.pipe(
R.map($),
R.forEach(addActive),
R.filter(notFaded),
R.filter(selecteded)
);
这似乎并没有改变很多处理过程。这很好!原语已经改变了,它们更简单,更容易看到发生了什么,但总体流程是相同的
现在是时候振作起来了。由于参数性,您可以将两个过滤器组合在一起,而不必担心它们是否有意义。有一条定律规定R.pipe(R.filter(p),R.filter(q))==R.pipe(R.filter(R.and(p,q))
。这意味着不必对数组进行两次过滤,只需过滤一次,然后依次应用谓词
var processList = R.pipe(
R.map($),
R.forEach(addActive),
R.filter(R.and(notFaded, selecteded))
);
如果addClass
没有对其参数进行变异,我们还可以使用参数将map
和forEach
组合成一个。我们可以通过使用以下参数创建自己的非变异addClass
来解决此问题:
因此,我们可以再次使用map!。管道可以更改为:
var processList = R.pipe(
R.map($),
R.map(newActive),
R.filter(R.and(notFaded, selecteded))
);
现在,我们可以使用参数将映射组合在一起。该定律规定R.pipe(R.map(f),R.map(g))==R.map(R.pipe(f,g))
。我们不在数组上映射两次,而是映射一次,然后依次在映射中组合函数。因此,我们的管道现在看起来如下所示:
var processList = R.pipe(
R.map(R.pipe($, newActive)),
R.filter(R.and(notFaded, selecteded))
);
我们还可以进行进一步的重构和优化。我们可以在映射之前进行过滤,这样我们就可以迭代更少的元素,或者将调用程序
调用抽象到一个小小的jquery包装器DSL。我们鼓励您继续重构,但这是一个很好的改变。每个函数都有一个非常重要的作用ittle更具可组合性、可测试性和可理解性
整个重构过程如下所示
之前:
var removeFadeItems = R.filter(function(x) {
return !$(x).hasClass('fade');
});
var takeFromSelected = R.filter(function(x) {
return $(x).hasClass('selected');
});
var addActiveClass = function(x) {
$(x).addClass('active');
};
var processList = R.pipe(
R.forEach(addActiveClass),
takeFromSelected,
removeFadeItems
);
processList(list);
之后:
var faded = R.invoker(1, 'hasClass', 'fade');
var selecteded = R.invoker(1, 'hasClass', 'selected');
var notFaded = R.not(faded);
var newActive = R.pipe(
R.invoker(0, 'clone'),
R.invoker(1, 'addClass', 'active')
);
var processList = R.pipe(
R.map(R.pipe($, newActive)),
R.filter(R.and(notFaded, selecteded))
);
processList(list);