【问题标题】:Compose in JavaScript, not applying functions correctly?用 JavaScript 编写,没有正确应用函数?
【发布时间】:2014-11-10 00:38:46
【问题描述】:

这是我的 compose 函数,作为一个 polyfill

Function.prototype.compose = function(prevFunc) {
    var nextFunc = this;
    return function() {
        return  nextFunc.call(this, prevFunc.apply(this,arguments));
    }
}

这些工作:

function function1(a){return a + ' do function1 ';}
function function2(b){return b + ' do function2 ';}
function function3(c){return c + ' do function3 ';}
var myFunction = alert(function1).compose(function2).compose(function3);
myFunction('do');

var roundedSqrt = Math.round.compose(Math.sqrt)
roundedSqrt(6);

var squaredDate = alert.compose(roundedSqrt).compose(Date.parse)
quaredDate("January 1, 2014");

但这不起作用!

var d = new Date();
var alertMonth = alert.compose(getMonth); <-- 
alertMonth(d);                   ^^^^

错误在谷歌浏览器中引发错误“未捕获的 ReferenceError:getMonth 未定义”。

现在,如果我尝试以下任何一种方法:

var d = new Date();
function pluckMonth(dateObject) {return dateObject.getMonth();}
var alertMonth = alert.compose(pluckMonth);
var alertMonth2 = alert.compose(function(d){return d.getMonth()});
alertMonth(d);
alertMonth2(d);

他们工作。

好的,那么,这是为什么呢?我不想编写额外的函数,我希望它能够正常工作。 compose 函数使用apply 实用程序,而this 仅用于thisArg,因此它应该适用于对象成员以及独立函数,对吧??

也就是说,它们是等价的

this.method()
method.call.apply(this)

jsFiddle: http://jsfiddle.net/kohq7zub/3/

【问题讨论】:

  • getMonth 不是函数,它是Date.prototype 的属性。
  • 试试compose(Date.prototype.getMonth)
  • 我有,我已经尝试了所有这些小技巧。如果您想自己尝试,我提供了一个 jsfiddle:jsfiddle.net/kohq7zub/3
  • 是的,我自己试过了,没用。问题是this 没有通过组合正确传播。我不确定您是否可以像这样等效地对待普通函数和方法。

标签: javascript methods function-composition modifier


【解决方案1】:

如果涉及到Function 对象的原型设计,一大堆库真的不承认函数是方法。

此类参数签名中的最后一个条目始终应该是target 对象,然后可以对其进行操作。它解决了实现中的绑定;从而避免以后不得不一次又一次地使用bind作为唯一的解决方案。

给定的example slightly needs to be changed (jsFiddle) 到...

Function.prototype.compose = function(prevFunc, target) {
  var nextFunc = this;
  return function() {
    return nextFunc.call(this, prevFunc.apply(target, arguments));
  };
};

const d = (new Date);
let alertMonth;

// both variants do work.

alertMonth = alert.compose(d.getMonth, d);
alertMonth();

alertMonth = alert.compose(Date.prototype.getMonth, d);
alertMonth();

在下一次代码迭代中,上面提供的代码可能会导致类似于以下实现的结果...

const protoGetMonth = Date.prototype.getMonth;
let logMonth;

logMonth = ((month) => console.log(month))
  .compose(protoGetMonth, (new Date));

logMonth();

logMonth = console.log
  .compose(protoGetMonth, (new Date))
  .bind(console);

logMonth();

let alertMonth = alert.compose(protoGetMonth, (new Date));
alertMonth();
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
  (function (function_prototype) {
    var
      isFunction = (function (TYPEOF_FUNCTION_TYPE) {
        return function (type) {
          return (
               (typeof type == TYPEOF_FUNCTION_TYPE)
            && (typeof type.call == TYPEOF_FUNCTION_TYPE)
            && (typeof type.apply == TYPEOF_FUNCTION_TYPE)
          );
        }
      }(typeof function_prototype)),

      getSanitizedTarget = function (target) {
        return (target == null) ? null : target;
      }
    ;
    function_prototype.compose = function (previous, target) { // compose
      var
        previousTarget = getSanitizedTarget(target),
        proceed = this
      ;
      return (isFunction(previous) && isFunction(proceed) && function () {

        return proceed.call(this, previous.apply(previousTarget, arguments));

      }) || proceed;
    };
  }(Function.prototype));
</script>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-27
    • 2017-11-13
    • 2019-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多