Javascript: currying function parameter without setting its function context

81 Views Asked by At

My understanding is that as per spec, the parameters set in bind() are final and cannot be overridden.

I would like to know if there is any way of achieving something like this, which fails to give me the results that I want:

const Student = {
    name: "",
    times: function(i, j) {
        return `I am: ${this.name} & think answer is: ${i*j}`;
    }
};

const student1 = {
    name: "student1"
}
const student2 = {
    name: "student2"
}

const askThemTimesBy10 = Student.times.bind(null, 10);

console.log(askThemTimesBy10.bind(student1)(5));
console.log(askThemTimesBy10.bind(student2)(5));

obviously this fails since the function-context is hard-coded at the time of currying.

Now I can clearly do hacks like:

askThemX10 = function(){
    return Student.times.bind(this, 10);
}

askThemXTen = function(i){
    return Student.times.call(this, 10, i);
}

and then use them like:

console.log(askThemX10.bind(student1)()(5));
console.log(askThemXTen.bind(student1)(5));

or I can define the curried function inside Student etc. etc. but I'd like to know if there is a nicer way of doing this.

2

There are 2 best solutions below

6
On

Any time you're thinking of using bind, you're probably doing something wrong. In this case, use a normal class:

class Student {
  constructor(name) {
    this.name = name;
  }

  multiply(i, j) {
    return `I am: ${this.name} & think answer is: ${i*j}`;
  }
}

and then create student instances:

const students = [
  new Student("alice"),
  new Student("bob"),
  ...
]

And then make that "... times 10" function either a global:

function askStudentX10(student, i) {
  return student.multiply(i, 10);
}

Or if you want to keep things nice and namespaced, make it a static function on the Student class:

class Student {
  static askStudentX10(student, i) {
    return student.multiply(i, 10);
  }

  constructor(name) {
    ...
  }

  ...
}

Nice and explicit code, no bind required, no potential bind-related bugs. Just plain, obvious, code.

1
On

Speaking of modern JS. If you can transpile your code and do not afraid to use experimental syntax, you may achieve what you want using partial application syntax. Not recommended for production though :)

Demo

const Student = {
    name: "",
    times(i, j) {
        return `I am: ${this.name} & think answer is: ${i*j}`;
    }
};

const student1 = {
    name: "student1"
}
const student2 = {
    name: "student2"
}

const askThemTimesBy10 = Student.times.call(?, 10, ?); // <--- pew pew 

console.log(askThemTimesBy10(student1, 5));
console.log(askThemTimesBy10(student2, 6));