【问题标题】:JavaScript function currying does not work on instance methodJavaScript 函数柯里化不适用于实例方法
【发布时间】:2013-03-24 20:14:56
【问题描述】:

我正在通过在线阅读和编写一些简单的代码来学习 JavaScript 中的函数柯里化。我在在线文章中得到了以下示例

    function toArray(obj) {
        return Array.prototype.slice.call(obj);
    }

    Function.prototype.curry = function() {
        if (arguments.length<1) {
            return this; //nothing to curry with - return function
        }
        var __method = this;
        var args = toArray(arguments);
        return function() {
            return __method.apply(this, args.concat(toArray(arguments)));
        }
    }

    var add = function(a,b) {
        return a + b;
    }

    var addTen = add.curry(10); //create function that returns 10 + argument
    alert(addTen(20)); //alerts 30 correctly

然后我尝试在实例化函数的方法上进行尝试。所以我试着跟随。但它在倒数第二行给了我错误“无法获取未定义或空引用的属性'原型'”。我知道这个错误与柯里化无关,但我搞砸了 JS 函数概念的一些基础知识。那么我哪里出错了。

    function Person()
    {
        this.age = 15;
    }

    Person.ageAfter = function (years) {
        return this.age + years;
    }

    var personObj = new Person();
    var ageAfterFiveYears = personObj.ageAfter.prototype.curry(5);  //**Error**
    alert(ageAfterFiveYears());

【问题讨论】:

  • personObj 没有属性 ageAfter。只有Person 有。我认为您的意思是将ageAfter 分配给Person.prototype.ageAfter,以便每个Person 实例都继承该函数。
  • @FelixKling 我认为这是一个转录错误,但您可能是对的,这是直接的问题。
  • @Pointy:这是我认为的问题之一。提到的错误消息““无法获取未定义或空引用的属性'原型'”支持这一点。
  • 这是我提到的问题之一。
  • 我想提一下,这不是正确的柯里化;这是部分应用。见:stackoverflow.com/questions/218025/…

标签: javascript function partial-application


【解决方案1】:

您不应在调用中包含原型:

var ageAfterFiveYears = personObj.ageAfter.curry(5);

“ageAfter”属性的值有一个函数,因此该函数可以访问“curry”函数,就像第一个示例中的函数一样。

当你在原型上调用它时,你函数中this的值将是原型对象,而不是“ageAfter”函数。

正如评论指出的那样,您需要在原型上加上“ageAfter”:

Person.prototype.ageAfter = function(years) { ... }

edit — Alnitak 指出的绑定问题也很重要。 (当我说“重要”时,我的意思是“使您的代码工作所必需的”。)

【讨论】:

  • @Mahesha999 没有修复绑定问题,这仍然不完整。
【解决方案2】:

你有两个问题:

  1. ageAfter 函数不是实例方法 - 您已将其添加到“类”中(即,它有点像静态方法)。它应该被添加到原型中。

  2. 当您对函数进行 curry 时,您会丢失对象的上下文,因此您要么需要重新绑定上下文

例如:

var ageAfterFiveYears = Person.prototype.ageAfter.curry(5).bind(personObj);

给你一个在当前实例上工作的函数,或者更好的是,正如@Pointy 在 cmets 中所建议的那样,你应该把 curried 函数放回原型:

Person.prototype.ageAfterFiveYears = Person.prototype.ageAfter.curry(5);

然后将.ageAfterFiveYears 方法添加到每个 Person 对象。

【讨论】:

  • 另外,调用“curry”的结果可以添加为实例的属性或“Person”原型,然后通过实例调用,就像调用“ageAfter”一样。
【解决方案3】:

Curry 不适用于您的用例。您需要绑定上下文,因此 this 是您的 personObj。

function Person() {
    this.age = 15;
}

Person.prototype.ageAfter = function (years) {
    return this.age + years;
}

var personObj = new Person();
var ageAfterFiveYears = personObj.ageAfter.bind(personObj, 5);
alert(ageAfterFiveYears());

【讨论】:

  • 请注意,虽然这有效,但它可能对 OP 没有用,因为它实际上并没有使用他的 .curry 函数。
  • 是的,我知道这种 bind() 方法也是函数柯里化,我之前尝试过,它有效,但只是想探索其他方式
猜你喜欢
  • 1970-01-01
  • 2016-01-01
  • 2021-02-07
  • 2012-10-06
  • 1970-01-01
  • 2016-05-12
  • 2018-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多