Partial application means fixing some of a function's arguments now and getting back a new function that takes the rest later. Calling the new function calls the original with the fixed arguments first, then the new ones. It saves repeating arguments that are always the same, and gives the more specific function a name of its own. Think of a form with the fields that never change already filled in: each time, you fill in only the rest.
const greet = (greeting, name) => `${greeting}, ${name}`;
// By hand: a new function with greeting fixed as "Hi"
const sayHi = (name) => greet("Hi", name);
sayHi("Ada"); // "Hi, Ada"
sayHi("Grace"); // "Hi, Grace"
// Built in: bind fixes this (null here), then any arguments from the left
const sayHello = greet.bind(null, "Hello");
sayHello("Ada"); // "Hello, Ada"
bind can only fix arguments from the left, and it fixes this as well. Lodash's _.partial leaves this alone: the new function passes on whatever this it's called with. It also takes a placeholder, _, that leaves a gap to fill later. The later call's arguments fill the gaps in order, any left over go after the fixed ones, and a gap with nothing left to fill it gets undefined.
| Fixed now | Called later with | So greet is called with |
|---|---|---|
_.partial(greet, "Hi") | "Ada" | greet("Hi", "Ada") |
_.partial(greet, _, "Ada") | "Hello" | greet("Hello", "Ada") |
_.partial(greet, _) | "Hey", "Ada" | greet("Hey", "Ada"): "Ada" was left over |
_.partial(greet, _, "Ada") | Nothing | greet(undefined, "Ada") |
Partial application isn't currying. A curried function takes its arguments over a chain of calls, f(a)(b)(c), and keeps returning functions until all of them have arrived. A partially applied function is an ordinary function again: one call with the remaining arguments runs it.
You meet it whenever a callback needs some arguments decided in advance: a click handler made for one item's ID, or prices.map((price) => format("GBP", price)), which fixes the currency by hand.
Write partial(fn, ...presetArgs). It returns a function that calls fn with the preset arguments followed by the new ones, and returns the result. The caller's this is passed on to fn.
partial.placeholder (defined in the starter) leaves a gap. Each preset that is the placeholder is filled with the next new argument, in order, and the new arguments that are left go at the end. A placeholder with no new argument left to fill it becomes undefined. The returned function can be called any number of times.
const greet = (greeting, name, mark) => greeting + ", " + name + mark;
partial(greet, "Hi")("Ada", "!"); // "Hi, Ada!"
const _ = partial.placeholder;
const askAda = partial(greet, _, "Ada", "?");
askAda("Hello"); // "Hello, Ada?"
askAda("Hey"); // "Hey, Ada?"
expect(partial((a, b, c) => [a, b, c], 1, 2)(3)).toEqual([1, 2, 3]);
expect(partial((a, b, c) => [a, b, c], 1)(2, 3)).toEqual([1, 2, 3]);
expect(partial((a, b) => a + b, 2, 3)()).toBe(5);
expect(partial((a, b) => a + b)(2, 3)).toBe(5);
const _ = partial.placeholder;
expect(partial((a, b, c) => [a, b, c], _, 2, _)(1, 3)).toEqual([1, 2, 3]);
const _ = partial.placeholder;
expect(partial((...args) => args, _, "b")("a", "c", "d")).toEqual(["a", "b", "c", "d"]);
const _ = partial.placeholder;
expect(partial((...args) => args, 1, _, 3)()).toEqual([1, undefined, 3]);
const obj = {
base: 10,
add: partial(function (a, b) {
return this.base + a + b;
}, 1),
};
expect(obj.add(2)).toBe(13);
const _ = partial.placeholder;
const greet = (greeting, name) => greeting + ", " + name;
const greetAda = partial(greet, _, "Ada");
expect(greetAda("Hello")).toBe("Hello, Ada");
expect(greetAda("Hey")).toBe("Hey, Ada");
Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.
Ctrl + Enter runs the tests (⌘ + Enter on a Mac).
I'm here to help with Partial application. I give hints, never the solution, so you get to solve it yourself. Ask for a hint, select code to ask about it, or press Ask Tuto why on a failing test.
Your first 3 answers need no account. for free to keep asking.