Question

I am learning function currying in JavaScript by reading online and writing some simple code. I got following example in online article

    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

Then I tried to try it on the method of an instantiated function. So I tried following. But it gave me error "Unable to get property 'prototype' of undefined or null reference" on the second last line. I know this error is nothing to do with currying but I am messing up with some basics of JS functions concept. So where I am going wrong.

    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());
Was it helpful?

Solution 2

You have two issues:

  1. The ageAfter function is not an instance method - you've added it to the "class" (i.e. it's kind of like a static method). It should be added to the prototype.

  2. When you curry the function you lose your object's context, so you either need to rebind the context

e.g:

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

giving you a function that only works on the current instance, or better yet, as @Pointy suggests in the comments, you should just put the curried function back onto the prototype:

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

which then adds the .ageAfterFiveYears method to every Person object.

OTHER TIPS

You shouldn't include the prototype in your call:

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

The "ageAfter" property has a function for its value, so that function will have access to your "curry" function just like the function in your first example.

When you call it on the prototype, the value of this inside your function will be the prototype object, not the "ageAfter" function.

Also as a comment points out, you need to put "ageAfter" on the prototype:

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

edit — the binding issue that Alnitak points out is also important. (When I say "important", what I mean is "necessary to make your code work".)

Curry will not work for your use case. You need to bind the context so this is your 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());
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top