我怎么能用Ramda.js更好地做到这一点

kev*_*gan 2 javascript functional-programming ramda.js

所以我有一个div列表: list

我想要一个列表的子集删除与.fade类的div .而且只是从.selected课堂上抓住div的列表.

所以使用R.takeWhileR.dropWhile.

然后我想映射该新列表并.active使用R.takeR.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);
Run Code Online (Sandbox Code Playgroud)

我对这个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)
Run Code Online (Sandbox Code Playgroud)

jon*_*shf 22

根据您的描述,听起来您想要使用filter超过takeWhiledropWhile.

takeWhile 保留数组的值,直到谓词第一次失败:

> R.takeWhile(R.isEmpty, [[], [], [1, 2, 3], [], [1, 3]])
[ [], [] ]
Run Code Online (Sandbox Code Playgroud)

dropWhile 删除数组的值,直到第一次谓词失败:

> R.dropWhile(R.isEmpty, [[], [], [1, 2, 3], [], [1, 3]])
[ [ 1, 2, 3 ], [], [ 1, 3 ] ]
Run Code Online (Sandbox Code Playgroud)

filter 删除所有未传递谓词的值.

> R.filter(R.isEmpty, [[], [], [1, 2, 3], [], [1, 3]])
[ [], [], [] ]
Run Code Online (Sandbox Code Playgroud)

在你的情况下你想要的东西:

var removeFadeItems = R.filter(function(x) {
  return !$(x).hasClass('fade');
});
var takeFromSelected = R.filter(function(x) {
  return $(x).hasClass('selected');
});
Run Code Online (Sandbox Code Playgroud)

另外,正如@donnut所说,你也map需要返回一个值.但是,你有点不好意思addClass.由于它改变了值(这是副作用),因此使用map有点用词不当.你最好不要使用forEach它,因为它是为了副作用而制作的:

var addActiveClass = function(x) {
  $(x).addClass('active');
};
Run Code Online (Sandbox Code Playgroud)

所以你最终得到:

var processList = R.pipe(
  R.forEach(addActiveClass),
  takeFromSelected,
  removeFadeItems
);
processList(list);
Run Code Online (Sandbox Code Playgroud)

重构

现在,由于你的某些函数是引用透明的(它们不会改变事物),你可以将它重构为更清晰,更可组合和更高效.

首先要注意的是你在每个函数中重写你的div.这$是一个很好的功能,只用一次包装东西.那么让我们开始管道.

var processList = R.pipe(
  R.map($),
  ...
Run Code Online (Sandbox Code Playgroud)

现在,invoker允许您调用对象上的函数.我们想addClass用参数来调用jquery包装的对象active.让我们为此做一个函数:

var addActive = R.invoker(1, 'addClass', 'active');
Run Code Online (Sandbox Code Playgroud)

我们可以将其添加到管道中.

var processList = R.pipe(
  R.map($),
  R.forEach(addActive),
  ...
Run Code Online (Sandbox Code Playgroud)

过滤器类似于我们所做的addActive,让我们首先通过使谓词分离来重构它们:

var faded = R.invoker(1, 'hasClass', 'fade');
var notFaded = R.not(faded);
var selecteded = R.invoker(1, 'hasClass', 'selected');
Run Code Online (Sandbox Code Playgroud)

这里最棒的是ramda函数的可组合性允许我们说R.not(faded),而事情只是工作而不考虑它.

所以我们将它添加到管道中.

var processList = R.pipe(
  R.map($),
  R.forEach(addActive),
  R.filter(notFaded),
  R.filter(selecteded)
);
Run Code Online (Sandbox Code Playgroud)

这似乎没有改变处理的大部分内容.这很好!原语已经改变,它们更简单,更容易看到发生了什么,但整体流程是相同的.

现在是时候变得令人兴奋了.由于参数化,您可以将两个滤波器组合在一起,而无需担心它们是否有意义.有一项法律规定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))
);
Run Code Online (Sandbox Code Playgroud)

如果addClass没有发生变异的说法,我们也可以使用parametricity要结合mapforEach融入其中.我们可以做我们自己的非不同诱变解决这个问题addClassclone:

var newActive = R.pipe(
  R.invoker(0, 'clone'), 
  R.invoker(1, 'addClass', 'active')
);
Run Code Online (Sandbox Code Playgroud)

所以我们可以再次使用地图!管道可以改为:

var processList = R.pipe(
  R.map($),
  R.map(newActive),
  R.filter(R.and(notFaded, selecteded))
);
Run Code Online (Sandbox Code Playgroud)

现在我们可以使用参数化将地图组合在一起.法律规定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))
);
Run Code Online (Sandbox Code Playgroud)

我们可以进行进一步的重构和优化.我们可以在映射之前进行过滤,因此我们最终会迭代更少的元素,或者将invoker调用抽象为一个小的jquery包装器DSL.我们鼓励你继续进行重构,但这是一个非常好的改变.每个函数都做得很少,更可组合,更可测试,更易理解.

整个重构如下.

之前:

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);
Run Code Online (Sandbox Code Playgroud)

后:

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);
Run Code Online (Sandbox Code Playgroud)