Crockford 的“curry”方法中的“this”无效是否有原因?

2024-04-15

在 Douglas Crockford 的书《Javascript:The Good Parts》中,他提供了curry方法接受一个函数和参数并返回已添加参数的函数(显然,这并不是真正的"咖喱"是什么意思 https://stackoverflow.com/tags/currying/info,但是是一个例子“部分应用” https://stackoverflow.com/tags/partial-application/info)。这是代码,我对其进行了修改,以便无需他编写的其他自定义代码即可运行:

Function.prototype.curry = function(){
  var slice = Array.prototype.slice,
      args = slice.apply(arguments),
      that = this;
  return function() {
    // context set to null, which will cause `this` to refer to the window
    return that.apply(null, args.concat(slice.apply(arguments)));
  };
};

所以如果你有一个add功能:

var add = function(num1, num2) {
  return num1 + num2;
};

add(2, 4);          // returns 6

您可以创建一个已有一个参数的新函数:

var add1 = add.curry(1);

add1(2);           // returns 3

效果很好。但我想知道的是他为什么要设置this to null?柯里化方法是否与原始方法相同(包括相同的内容)不是预期的行为吗?this?

我的咖喱版本看起来像这样:

Function.prototype.myCurry = function(){
  var slice = [].slice,
      args = slice.apply(arguments),
      that = this;
  return function() {
    // context set to whatever `this` is when myCurry is called
    return that.apply(this, args.concat(slice.apply(arguments)));
  };
};

Example

(这是示例的jsfiddle) http://jsfiddle.net/38z2r/5/

var calculator = {
  history: [],
  multiply: function(num1, num2){
    this.history = this.history.concat([num1 + " * " + num2]);
    return num1 * num2;
  },
  back: function(){
    return this.history.pop();
  }
};

var myCalc = Object.create(calculator);
myCalc.multiply(2, 3);         // returns 6
myCalc.back();                 // returns "2 * 3"

如果我尝试按照道格拉斯·克罗克福德的方式去做:

myCalc.multiplyPi = myCalc.multiply.curry(Math.PI);
myCalc.multiplyPi(1);          // TypeError: Cannot call method 'concat' of undefined

如果我按照自己的方式去做:

myCalc.multiplyPi = myCalc.multiply.myCurry(Math.PI);
myCalc.multiplyPi(1);          // returns 3.141592653589793
myCalc.back();                 // returns "3.141592653589793 * 1"

然而,我觉得如果道格拉斯·克罗克福德按照他的方式这样做,他可能有充分的理由。我缺少什么?


原因1-不容易提供通用的解决方案

问题是你的解决方案不通用。如果调用者没有将新函数分配给任何对象,或者将其分配给完全不同的对象,则您的multiplyPi函数将停止工作:

var multiplyPi = myCalc.multiply.myCurry(Math.PI);
multiplyPi(1);  // TypeError: this.history.concat is not a function

因此,Crockford 和您的解决方案都不能确保该函数能够正确使用。那么可以更容易地说curryfunction 仅适用于“函数”,不适用于“方法”,并且设置this to null强迫这样做。不过,我们可能只是猜测,因为克罗克福德在书中没有提到这一点。

原因 2 - 正在解释功能

如果你问“为什么 Crockford 不使用这个或那个” - 很可能的答案是:“就已证明的问题而言,这并不重要。”Crockford 在本章中使用了这个例子功能。分章的目的curry was:

  • 表明函数是可以创建和操作的对象
  • 演示闭包的另一种用法
  • 展示如何操纵参数。

针对对象的一般用法进行微调并不是本章的目的。因为即使不是不可能,也是有问题的(参见原因 1),因此将其放在那里更具教育意义null相反,如果放在那里某物这可能会引发问题,如果它真的有效或无效(但对你的情况没有帮助:-))。

结论

也就是说,我认为您可以对自己的解决方案充满信心!对于您的情况,没有特别的理由遵循 Crockfords 的重置决定this to null. 但您必须注意,您的解决方案仅在某些情况下有效,并且不是 100% 干净。那么干净的“面向对象”解决方案将是询问对象在其内部创建其方法的克隆,以确保生成的方法将保留在同一个对象内。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Crockford 的“curry”方法中的“this”无效是否有原因? 的相关文章

随机推荐