代码之家  ›  专栏  ›  技术社区  ›  Austin Hyde

Functional JavaScript:如何实现Function.prototype.not

  •  7
  • Austin Hyde  · 技术社区  · 16 年前

    今天早些时候我正在写代码,突然意识到,“嘿!如果我将布尔值的概念从匿名函数中抽象出来,并将其转化为原型函数,那么这段代码将更加简洁和语义化……”

    考虑谓词生成器:

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

    所以你可以这样使用它:

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

    现在,我的想法是做一个谓词“inverser”:

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

    所以你可以说:

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

    我对实现的第一次尝试可能非常幼稚:

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

    也可能是它不起作用的原因。

    你将如何实现这个功能,为什么?

    我只是试着把我的头脑放在函数思想上,并且对JavaScript有足够的了解,知道它可以用来做这件事,但只是不知道如何做。

    3 回复  |  直到 16 年前
        1
  •  8
  •   SLaks    16 年前

    由于以下几个原因,您的实现无法工作:

    • 您需要返回一个函数,而不是布尔值。
    • 你应该保留上下文( this

    我会这样实施:

    Function.prototype.not = function (context) {
        var func = this;
        return function() { return !func.apply(context || this, arguments); };
    }
    
    • 我返回一个匿名函数( function() { ... } )
    • 我打电话来 apply 使用实际参数在当前上下文中调用原始函数。
    • 编辑 )免费奖金:我增加了一个可选的 context 将覆盖的参数 为了回拨。
        2
  •  2
  •   Thomas Eding    16 年前

    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)));
    
        3
  •  1
  •   Casey Chu    16 年前

    运用你的想法:

    function equalTo(n) {
        var fn = function(x) {
            return n == x;
        };
        fn.not = function(x) {
            return n != x; // use this for simpler conditions
            return !fn.apply(this, arguments); // use this for more complex logic
        }
        return fn;
    }
    

    所以你的例子是可行的:

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

    :您可以编写一个助手函数(可以找到更好的名称),以便 not 不需要每次都重新定义:

    function generateFnWithNot(fn) {
        return function () {
            var f = fn.apply(this, arguments);
            f.not = function () {
                return !f.apply(this, arguments);
            }
            return f;
        };
    }
    

    generateFnWithNot 电话:

    var equalTo = generateFnWithNot(function (n) {
        return function (x) {
            return n == x;
        };
    });
    
    equalTo(5) // resolves to function () { return n == 5; }
    equalTo(5).not // resolves to function () { return n != 5; } 
    
    推荐文章