3

Given 是一个具有一系列条件的对象:

var conditions = {
    even: function (i) { return i % 2 == 0; },

    greatherThan: function (i) { return i > 10; },

    inValidRange: function (i) {
        return i > 20 && i < 100;
    }
};

以及从 0 到 39 范围内的数组编号:var numbers = _.range(0, 40);

我想numbers按每个条件过滤。我使用 underscore.js 来做到这一点:

var result = _.filter(numbers, function(current) {

    return _.all(_.values(conditions), function(f) { 
        return f(current);
    });

});
// returns [ 22, 24, 26, 28, 30, 32, 34, 36, 38 ]

它工作正常,但不幸的是,上面的代码看起来很奇怪,而且很混乱。

如何简化此代码以使其更具可读性和可理解性?

4

2 回答 2

4

这个辅助函数可能有用:

_.mixin({
    invokeWith: function() {
        var args = arguments;
        return function(fn) {
             return fn.apply(null, args);
        };
    }
});

conditions如果您立即成为一个数组,那也会更好。您可以使用一组命名函数:

var conditions = [
    function even(i) { return i % 2 == 0; },
    function greaterThan(i) { return i > 10; },
    function inValidRange(i) { return i > settings.validRange.from && i < settings.validRange.to; }
];

或者之前改造一下,这样我们就可以省略(也不需要重复调​​用)这个values函数:

conditions = _.values(conditions);

现在您可以将代码缩短为

var result = _.filter(numbers, function(current) {
    return _.all(conditions, _.invokeWith(current));
});

理解会发生什么可能会更复杂,因为大多数人必须查找该invokeWith函数,但这个概念更容易掌握,因为代码是非常声明性的,包含所有动词来构建自然表达式调用所有条件 withcurrent

如果还想删除外部 lambda 表达式,它会变得更短但更难理解:

// functional programming FTW :-)
var result = _.filter(numbers, _.compose(_.partial(_.all, conditions), _.invokeWith));
于 2013-08-15T19:17:28.420 回答
0

无需重写该代码;把它放在一个命名函数中:

function filterByConditions(values, conditions){
  return _.filter(values, function(current) {

    return _.all(_.values(conditions), function(f) { 
      return f(current);
    });

  });
}

函数中的代码并不复杂,不应该让熟悉 underscore.js 的人感到困惑。如果您认为有必要,您可以在函数体中添加注释。无论哪种方式,当您在其他地方使用该函数时,应该从名称中清楚该函数的作用:

var result = filterByConditions(numbers, conditions);

如果你想简化函数的主体,让不熟悉 underscore.js 的开发者仍然可以阅读它,你可以_all_values一个简单的 for ... in循环替换它。大多数 Javascript 开发人员无需使用 underscore.js就可以推断出_.filter的作用:

function filterByConditions(values, conditions){
  return _.filter(values, function(current){

    for(condition_name in conditions){

      if(!conditions[condition_name](current)){
        // Condition failed
        return false;
      }

    }

    // All conditions passed
    return true;

  });
}
于 2013-08-15T19:06:46.457 回答