JS调用函数时如何使用逻辑非(!)运算符?

How do I use the logical NOT (!) operator when invoking functions in JS?

我正在从下划线库中重新创建函数,但在尝试实现 _.reject() 函数时 运行 遇到了障碍。出于这个问题的目的,我将包含我为三个函数编写的代码:_.each()_.filter()_.reject().

_.each = function(collection, iterator) {
  if (Array.isArray(collection)) {
    for (var i = 0; i < collection.length; i++) {
      iterator(collection[i], i, collection);
    }
  } else {
    for (var i in collection) {
      iterator(collection[i], i, collection);
    }
  }
};

_.filter = function(collection, test) {
    var results = [];

    _.each(collection, function(i) {
      if (test(i)) {
        results.push(i);
      }
    })

    return results;
};

这是我遇到问题的函数的代码,_.reject() 方法,以及我作为 [=18= 传入的 isEven() 函数] 参数。

_.reject = function(collection, test) {
    return _.filter(collection, !test);
}; 

var isEven = function(x) {
    if (x % 2 === 0) return true;
    return false;
};

根据 MDN's page on Expressions and Operators,逻辑非 (!) 运算符 Returns false if its single operand can be converted to true; otherwise, returns true.

但是当我 运行 下面的代码 _.reject([1,2,3], isEven) 时,我收到一条错误消息说 test is not a function。为什么我在调用函数时无法使用 ! 运算符(例如 _.filter([1,2,3], !isEven))?

你不能否定一个函数。这是一件毫无意义的事情(除非你真的想要值 false 而不输入它)。相反,您想否定函数的 return 值。我怀疑你想要的是这样的

_.reject = function(collection, test) {
  return _.filter(collection, function(e) { return !test(e); });
}

Why am I unable to use the ! operator while invoking a function (e.g., _.filter([1,2,3], !isEven))?

请注意,您实际上并没有调用 isEven,您只是在引用它。正如你所说,!"Returns false if its single operand can be converted to true; otherwise, returns true."

isEven 是对函数(即对象)的引用。对象转换为 true,因此 !test 结果为 false:

_.filter([1,2,3], false))

现在您将布尔值而不是函数传递给 _.filter,因此出现错误消息 "test is not a function".

相反,您必须传递一个否定测试函数结果的函数:

_.filter([1,2,3], function() {
    return !test.apply(this, arguments);
});

当您引用函数而不是调用它时,您指的是函数的对象引用:

function foo() {
    alert("Hi there");
}

var f = foo; // <== Getting the function's reference, not calling it
f();         // <== Now we call it

所以 !isEven 将否定函数引用。由于 isEven 是一个非 null 引用,所以它是真实的;所以 !isEvenfalse。不是你想要的。 :-)

您的 reject 可以用调用 test 并反转其 return 值的函数编写:

_.reject = function(collection, test) {
  return _.filter(collection, function(e) { return !test(e); });
};

或者如果你想使用函数式编程方法,你可以编写一个函数,当调用时,将 return 一个 new 函数来否定 return 值:

function not(f) {
    return function() {
        return !f.apply(this, arguments);
    };
}

然后在任何你想反转回调的含义的地方,你只需使用 invert:

_.reject = function(collection, test) {
  return _.filter(collection, not(test));
};