Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional JavaScript: how to implement Function.prototype.not

I was working on some code earlier today, when I realized, "Hey! This code would be more concise and semantic if I abstracted the idea of a boolean not out of an anonymous function and into a prototype function..."

Consider a predicate generator:

function equalTo(n) {
    return function(x) {
        return n==x;
    };
}

So you can use it like so:

[1,2,3,4,1,2,3,4].filter(equalTo(2)) == [2,2]

Now, my idea is to make a predicate "inverser":

Function.prototype.not = function() {
    //???
}

So that you can say:

[1,2,3,4,1,2,3,4].filter(equalTo(2).not) == [1,3,4,1,3,4]

My first stab at the implementation was probably very naive:

Function.prototype.not = function () {
    return ! this(arguments);
}

And probably why it didn't work.

How would you implement this function, and why?

I'm just trying to wrap my head around functional ideas, and know JavaScript well enough to know it can be used to do this, but just not how.

like image 270
Austin Hyde Avatar asked Jul 21 '10 01:07

Austin Hyde


People also ask

What are the 3 types of functions in JavaScript?

There are 3 ways of writing a function in JavaScript: Function Declaration. Function Expression. Arrow Function.

Do functions have prototype JavaScript?

A Function object's prototype property is used when the function is used as a constructor with the new operator. It will become the new object's prototype. Note: Not all Function objects have the prototype property — see description.

Which object in JavaScript does not have a prototype?

JavaScript has two types of objects: function object and non-function object. Conceptually, all objects have a prototype (NOT A PROTOTYPE PROPERTY).

Does function have prototype?

Every function has the "prototype" property even if we don't supply it. The default "prototype" is an object with the only property constructor that points back to the function itself.


2 Answers

Your implementation won't work for several reasons:

  • You need to return a function, not a boolean.
  • You should pass the arguments as-is, not wrapped in an array.
  • You should preserve the context (this keyword) that the function would have been called in.

I would implement it like this:

Function.prototype.not = function (context) {
    var func = this;
    return function() { return !func.apply(context || this, arguments); };
}
  • I return an anonymous function (function() { ... })
  • I call apply to call the original function in the current contexts with the actual arguments.
  • (EDIT) Free bonus: I added an optional context parameter which will override this for the callback.
like image 86
SLaks Avatar answered Oct 04 '22 19:10

SLaks


I would probably do it like so (but perhaps with some sort of namespacing):

function not (x) {
  return !x;
}

function id (x) {
  return x;
}

function compose (/*funcs*/) {
  var args = arguments.length
    ? Array.prototype.slice.call (arguments)
    : [id]
    ;
  return function () {
    var val = args [args.length - 1].apply (null, arguments);
    for (var i = args.length - 2; i >= 0; --i) {
      val = args [i] (val);
    }
    return val;
  };
}

[1,2,3,4,1,2,3,4].filter (compose (not, equalTo (2)));
like image 37
Thomas Eding Avatar answered Oct 04 '22 21:10

Thomas Eding