Skip to content

函数

记忆函数 II

js
class CacheNode {
  result = undefined;
  children = undefined;
  constructor(result, children) {
    this.result = result;
    this.children = children ?? new Map();
  }
}

function memoize(fn) {
  const root = new CacheNode();
  return function (...args) {
    let parentNode = root;
    for (const arg of args) {
      let childNode = parentNode.children.get(arg);
      if (!childNode) {
        parentNode.children.set(arg, (childNode = new CacheNode()));
      }
      parentNode = childNode;
    }
    if (parentNode.result === undefined) {
      parentNode.result = fn.apply(this, args);
    }
    return parentNode.result;
  };
}

柯里化

js
function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    }
    return function (...rest) {
      return curried.apply(this, args.concat(rest));
    };
  };
}

记忆函数

js
function memoize(fn) {
  const cachedResult = new Map();
  return function (...args) {
    const { length } = args;
    let parentMap = cachedResult;
    for (let i = 0; i < length - 1; ++i) {
      let childMap = parentMap.get(args[i]);
      if (!childMap) {
        parentMap.set(args[i], (childMap = new Map()));
      }
      parentMap = childMap;
    }
    let result = parentMap.get(args[length - 1]);
    if (result === undefined) {
      parentMap.set(args[length - 1], (result = fn(...args)));
    }
    return result;
  };
}

使用自定义上下文调用函数

js
function generateUniqueFunctionName() {
  return `callPolyfill_${Date.now()}_${Math.ceil(Math.random() * 100000)}`;
}

Function.prototype.callPolyfill = function (context, ...args) {
  const key = generateUniqueFunctionName();
  Object.defineProperty(context, key, {
    value: this,
    configurable: true,
  });
  const res = context[key](...args);
  delete context[key];
  return res;
};

将函数绑定到上下文

js
Function.prototype.bindPolyfill = function (obj) {
  const fn = this;
  return function (...args) {
    return fn.apply(obj, args);
  };
};

计数器

js
function createCounter(n) {
  let cnt = n;
  return function () {
    return cnt++;
  };
}

复合函数

js
function compose(functions) {
  return function (x) {
    let res = x;
    for (let i = functions.length - 1; i >= 0; --i) {
      res = functions[i](res);
    }
    return res;
  };
}

计数器 II

js
function createCounter(init) {
  let count = init;
  return {
    increment: () => ++count,
    decrement: () => --count,
    reset: () => (count = init),
  };
}

只允许一次函数调用 44

js
function once(fn) {
  let isCalled = false;
  return function (...args) {
    if (!isCalled) {
      isCalled = true;
      return fn.apply(this, args);
    }
  };
}

创建 Hello World 函数

js
function createHelloWorld() {
  return function (...args) {
    return 'Hello World';
  };
}

返回传递的参数的长度

js
function argumentsLength(...args) {
  return args.length;
}

相等还是不相等

js
function expect(val) {
  return {
    toBe: otherVal => {
      if (val === otherVal) {
        return true;
      }
      throw 'Not Equal';
    },
    notToBe: otherVal => {
      if (val !== otherVal) {
        return true;
      }
      throw 'Equal';
    },
  };
}

执行可取消的延迟函数

js
function cancellable(fn, args, t) {
  let isCanceled = false;
  setTimeout(() => {
    if (!isCanceled) {
      fn(...args);
    }
  }, t);
  const cancelFn = () => {
    isCanceled = true;
  };
  return cancelFn;
}

间隔取消

js
function cancellable(fn, args, t) {
  fn(...args);
  const intervalId = setInterval(() => {
    fn(...args);
  }, t);
  const cancelFn = () => {
    clearInterval(intervalId);
  };
  return cancelFn;
}

带有占位符的部分函数

js
function partial(fn, args) {
  const placeholders = args
    .map((arg, i) => i)
    .filter(i => args[i] === '_');
  return function (...restArgs) {
    let j = 0;
    for (const i of placeholders) {
      args[i] = restArgs[j++];
    }
    return fn.apply(this, args.concat(restArgs.slice(j)));
  };
}

参数不定、可链式调用的加法函数

js
function add(...args) {
  let sum = 0;

  const addInner = (...args) => {
    if (!args.length) {
      return sum;
    }
    sum += args.reduce((res, num) => res + num, 0);
    return addInner;
  };

  return addInner(...args);
}

console.log(add(1)(2, 3)()); // 6
console.log(add(1, 2)(3)(4)()); // 10