admin管理员组

文章数量:1287790

I'm re-creating functions from the underscore library but I'm running into a roadblock while trying to implement the _.reject() function. For the purposes of this question, I'll include the code I've written for three functions: _.each(), _.filter(), and _.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;
};

And here's the code for the function that I'm getting a problem with, the _.reject() method, along with the isEven() function that I'm passing in as the test argument.

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

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

According to MDN's page on Expressions and Operators, the Logical NOT (!) operator Returns false if its single operand can be converted to true; otherwise, returns true.

But when I run the following code _.reject([1,2,3], isEven) I get an error saying that test is not a function. Why am I unable to use the ! operator while invoking a function (e.g., _.filter([1,2,3], !isEven))?

I'm re-creating functions from the underscore library but I'm running into a roadblock while trying to implement the _.reject() function. For the purposes of this question, I'll include the code I've written for three functions: _.each(), _.filter(), and _.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;
};

And here's the code for the function that I'm getting a problem with, the _.reject() method, along with the isEven() function that I'm passing in as the test argument.

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

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

According to MDN's page on Expressions and Operators, the Logical NOT (!) operator Returns false if its single operand can be converted to true; otherwise, returns true.

But when I run the following code _.reject([1,2,3], isEven) I get an error saying that test is not a function. Why am I unable to use the ! operator while invoking a function (e.g., _.filter([1,2,3], !isEven))?

Share Improve this question asked Sep 22, 2015 at 15:42 giwookgiwook 5804 gold badges11 silver badges23 bronze badges 3
  • Sounds like perhaps you want !test() instead. Negating a function is meaningless. Negating a function's return value is more useful. – CollinD Commented Sep 22, 2015 at 15:43
  • Ah, I thought that negating the function a la !isEven would negate the return value. – giwook Commented Sep 22, 2015 at 15:45
  • I've posted an answer that may provide a solution. let me know how that goes. – CollinD Commented Sep 22, 2015 at 15:46
Add a ment  | 

3 Answers 3

Reset to default 7

When you refer to a function, rather than calling it, you're referring to the function's object reference:

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

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

So !isEven would be negating the function reference. Since isEven is a non-null reference, it's truthy; and so !isEven is false. Not what you want. :-)

Your reject could be written with a function that calls test and inverts its return value:

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

Or if you want to go the functional programming approach, you can write a function that, when called, will return a new function that negates the return value:

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

Then anywhere you want to invert a callback's meaning, you'd just use invert:

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

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

Note that you are actually not invoking isEven, you are merely referencing it. As you said, ! "Returns false if its single operand can be converted to true; otherwise, returns true."

isEven is a reference to a function, i.e. an object. Objects convert to true, hence !test results in false:

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

Now you are passing a Boolean instead of a function to _.filter, hence the error message "test is not a function".

Instead, you have to pass a function that negates the result of the test function:

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

You cannot negate a function. It's a meaningless thing to do (unless you really want the value false without typing it). Instead you want to negate the function's return value. I suspect what you want is something like so

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

本文标签: javascriptHow do I use the logical NOT () operator when invoking functions in JSStack Overflow