10

What is the equivalent for Pythons functools.partial in Javascript or jQuery ?

Zitrax
  • 19,036
  • 20
  • 88
  • 110

4 Answers4

6

ES6 solution

Here is a simple solution that works for ES6. However, since javascript doesn't support named arguments, you won't be able to skip arguments when creating a partial.

const partial = (func, ...args) => (...rest) => func(...args, ...rest);

Example

const greet = (greeting, person) => `${greeting}, ${person}!`;
const greet_hello = partial(greet, "Hello");

>>> greet_hello("Universe");
"Hello, Universe!"
David Callanan
  • 5,601
  • 7
  • 63
  • 105
  • 1
    I'm new to python and when i first heard about partial the first thing that came to mind was bind, after seeing this answer it basically looks like bind, `greet.bind(null, 'Hello')` , please correct me if i'm wrong but this achieves the same goal as the partial function solution you have provided, with the same restriction to not being able to skip arguments and an additional ugly `null` argument for the this arg. – Kostyantin2216 Dec 24 '19 at 15:59
  • @Kostyantin2216 Seems like you are right, but can't confirm – David Callanan Dec 24 '19 at 18:26
  • MDN explicitly makes a reference to partial functions using `bind`: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#partially_applied_functions – Stefan_EOX Oct 17 '22 at 11:55
5

Something like this perhaps. It is a little bit tricky as javascript doesn't have named arguments like python, but this function comes pretty close.

function partial() {
  var args = Array.prototype.slice.call(arguments);
  var fn = args.shift();
  return function() {
    var nextArgs = Array.prototype.slice.call(arguments);
    // replace null values with new arguments
    args.forEach(function(val, i) {
      if (val === null && nextArgs.length) {
        args[i] = nextArgs.shift();
      }
    });
    // if we have more supplied arguments than null values
    // then append to argument list
    if (nextArgs.length) {
      nextArgs.forEach(function(val) {
        args.push(val);
      });
    }
    return fn.apply(fn, args);
  }
}

// set null where you want to supply your own arguments
var hex2int = partial(parseInt, null, 16);
document.write('<pre>');
document.write('hex2int("ff") = ' + hex2int("ff") + '\n');
document.write('parseInt("ff", 16) = ' + parseInt("ff", 16));
document.write('</pre>');
hampusohlsson
  • 10,109
  • 5
  • 33
  • 50
  • Btw I also found https://github.com/azer/functools which has an [implementation](https://github.com/azer/functools/blob/4db1708/lib/functools.js#L261-L268). – Zitrax Oct 23 '15 at 12:32
2

To have the ES6 Solution also support classes:

const isClass = function (v) {
  // https://stackoverflow.com/a/30760236/2314626
  return typeof v === "function" && /^\s*class\s+/.test(v.toString());
};

const partial = (func, ...args) => {
  return (...rest) => {
    if (isClass(func)) {
      return new func(...args, ...rest);
    }
    return func(...args, ...rest);
  };
};

To use:

class Test {
  constructor(a, b, c) {
    this.a = a;
    this.b = b;
    this.c = c;
  }
}

const partialClass = partial(Test, "a");
const instance = partialClass(2, 3);
console.log(instance);

output:

➔ node tests/test-partial.js
Test { a: 'a', b: 2, c: 3 }
glen
  • 1,657
  • 19
  • 19
0

Here's an example using lodash:

const _ = require("lodash");

const greet = (greeting, person) => `${greeting}, ${person}!`;
const greet_hello = _.partial(greet, "Hello");

> greet_hello('John')
'Hello, John!'
asdf
  • 49
  • 1
  • 5