方法Function

MicLon2022年8月10日
大约 3 分钟

Box handler

JavaScript version

const boxHandler = (x) => ({ next: (f) => boxHandler(f(x)), done: (f) => f(x) });

Examples

// First example
const getPercentNumber = (str) =>
    boxHandler(str)
        .next((str) => str.replace(/\%/, ''))
        .next((str) => parseFloat(str))
        .done((res) => res * 0.01);

getPercentNumber('50%'); // 0.5

// Second example
const getMoney = (price) => Number.parseFloat(price.replace(/\$/, ''));
const getPercent = (percent) => Number.parseFloat(percent.replace(/\%/)) * 0.01;

const getDiscountPrice = (price, discount) =>
    boxHandler(getMoney(price))
        .done((cents) => boxHandler(getPercent(discount)).next((save) => cents - cents * save))
        .done((res) => res);

getDiscountPrice('$6.00', '20%'); // 4.8

Check if a value is a function

JavaScript version

const isFunction = (v) => ['[object Function]', '[object GeneratorFunction]', '[object AsyncFunction]', '[object Promise]'].includes(Object.prototype.toString.call(v));

Examples

isFunction(function () {}); // true
isFunction(function* () {}); // true
isFunction(async function () {}); // true

Check if a value is a generator function

JavaScript version

const isGeneratorFunction = (v) => Object.prototype.toString.call(v) === '[object GeneratorFunction]';

Examples

isGeneratorFunction(function () {}); // false
isGeneratorFunction(function* () {}); // true

Check if a value is an async function

JavaScript version

const isAsyncFunction = (v) => Object.prototype.toString.call(v) === '[object AsyncFunction]';

Examples

isAsyncFunction(function () {}); // false
isAsyncFunction(function* () {}); // false
isAsyncFunction(async function () {}); // true

Compose functions from left to right

JavaScript version

// Compose functions from left to right
const pipe =
    (...fns) =>
    (x) =>
        fns.reduce((y, f) => f(y), x);

Examples

const lowercase = (str) => str.toLowerCase();
const capitalize = (str) => `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
const reverse = (str) => str.split('').reverse().join('');

const fn = pipe(lowercase, capitalize, reverse);

// We will execute `lowercase`, `capitalize` and `reverse` in order
fn('Hello World') === 'dlrow olleH';

Compose functions

JavaScript version

// Compose functions from right to left
const compose =
    (...fns) =>
    (x) =>
        fns.reduceRight((y, f) => f(y), x);

Examples

const lowercase = (str) => str.toLowerCase();
const capitalize = (str) => `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
const reverse = (str) => str.split('').reverse().join('');

const fn = compose(reverse, capitalize, lowercase);

// We will execute `lowercase`, `capitalize` and `reverse` in order
fn('Hello World') === 'dlrow olleH';

Create a function that accepts a single argument

JavaScript version

const unary = (fn) => (arg) => fn(arg);

Examples

['1', '2', '3', '4', '5'].map(unary(parseInt)); // [1, 2, 3, 4, 5]

Create an empty function

JavaScript version

const noop = () => {};

// Or
const noop = Function();
// calling Function() might be detected as using eval by some security tools

Curry a function

JavaScript version

const curry = (fn, ...args) => (fn.length <= args.length ? fn(...args) : curry.bind(null, fn, ...args));

Examples

const sum = (a, b, c) => a + b + c;
curry(sum)(1)(2)(3); // 6
curry(sum)(1, 2, 3); // 6
curry(sum, 1)(2, 3); // 6
curry(sum, 1)(2)(3); // 6
curry(sum, 1, 2)(3); // 6
curry(sum, 1, 2, 3); // 6

Delay the evaluation of a function

JavaScript version

// returns a new version of `fn` that returns values as lazy evaluable
const thunkfy =
    (fn) =>
    (...args) =>
    () =>
        fn(...args);

Examples

const heavyComputation = (x) => doStuff(x);
const unnecessarySlow = manyThings.map(heavyComputation).find((result) => result.criteria);
const probablyFaster = manyThings.map(thunkfy(heavyComputation)).find((thunk) => thunk().criteria);

Execute a function once

JavaScript version

const once = (fn) =>
    (
        (ran = false) =>
        () =>
            ran ? fn : ((ran = !ran), (fn = fn()))
    )();

Examples

let n = 0;
const incOnce = once(() => ++n);
incOnce(); // n = 1
incOnce(); // n = 1
incOnce(); // n = 1

Flip the arguments of a function

JavaScript version

// Reverse the order of arguments
const flip =
    (fn) =>
    (...args) =>
        fn(...args.reverse());

// For binary functions
const flip = (fn) => (b, a) => fn(a, b);

// Or for curried functions
const flip = (fn) => (b) => (a) => fn(a)(b);

Examples

const isParent = (parent, child) => parent.children.includes(child);
const isChild = flip(isParent);

Identity function

JavaScript version

const identity = (x) => x;

Logical xor operator

JavaScript version

// returns `true` if one of the arguments is truthy and the other is falsy

const xor = (a, b) => (a && !b) || (!a && b);

// Or
const xor = (a, b) => !(!a && !b) && !(a && b);

// Or
const xor = (a, b) => Boolean(!a ^ !b);

Examples

xor(true, true); // false
xor(false, false); // false
xor(true, false); // true
xor(false, true); // true

Memoize a function

JavaScript version

const memoize = (fn) =>
    (
        (cache = Object.create(null)) =>
        (arg) =>
            cache[arg] || (cache[arg] = fn(arg))
    )();

Examples

// Calculate Fibonacci numbers
const fibo = memoize((n) => (n <= 2 ? 1 : fibo(n - 1) + fibo(n - 2)));

fibo(1); // 1
fibo(2); // 1
fibo(3); // 2
fibo(4); // 3
fibo(5); // 5
fibo(6); // 8

Partially apply a function

JavaScript version

const partial =
    (fn, ...a) =>
    (...b) =>
        fn(...a, ...b);

Examples

const sum = (x, y) => x + y;
const inc = partial(sum, 1);
inc(9); // 10

Uncurry a function

JavaScript version

// `fn` is a curried function
// `n` is the depth of parameters
const uncurry =
    (fn, n = 1) =>
    (...args) =>
        (
            (acc) => (args) =>
                args.reduce((x, y) => x(y), acc)
        )(fn)(args.slice(0, n));

Examples

const sum = (a) => (b) => (c) => a + b + c;
uncurry(sum, 1)(1)(2)(3); // 6
uncurry(sum, 2)(1, 2)(3); // 6
uncurry(sum, 3)(1, 2, 3); // 6

Loading...