Skip to content

基础概念

  1. 纯函数的定义是什么?为什么在函数式编程中纯函数很重要?

    • 纯函数:相同输入永远返回相同输出,不依赖外部状态,也不产生副作用。
    • 重要性:提高可预测性、可测试性、可复用性,便于并行计算。
  2. 解释什么是引用透明性,并给出 JavaScript 示例。

    • 概念:表达式可以被它的值替换而不影响程序行为。

    • 示例

      javascript
      const add = (a, b) => a + b;
      const result = add(2, 3);
      console.log(result); // 5
  3. 不可变性在函数式编程中的作用?

    • 保证数据不会被意外修改 → 降低副作用和调试难度。
    • 例子:用 map 创建新数组,而不是修改原数组。
  4. JavaScript 中函数是一等公民是什么意思?

    • 函数可以像值一样:存变量、当参数、当返回值。

    • 示例

      javascript
      let log = fn => x => { console.log(x); return fn(x); };
      
      // 等价
      function log {
        return function(x) {
          console.log(x);
          return fn(x);
        }
      }
  5. 声明式 vs 命令式

    • 命令式:告诉“怎么做”(for 循环)。

    • 声明式:告诉“做什么”(map、filter)。

    • 示例

      javascript
      // 命令式
      let numbers = [1, 2, 3, 4, 5];
      let sum = 0;
      for (let i = 0; i < numbers.length; i++) {
        sum += numbers[i];
      }
      
      // 声明式
      let numbers = [1, 2, 3, 4, 5];
      let sum = numbers.reduce((acc, curr) => acc + curr, 0);
  6. 解释什么是高阶函数,并给出 JavaScript 示例。

    • 概念:接受函数作为参数或返回函数的函数。

    • 示例

      javascript
      const map = (arr, fn) => arr.map(fn);
      const numbers = [1, 2, 3, 4, 5];
      const doubled = map(numbers, x => x * 2);
  7. 解释什么是柯里化,并给出 JavaScript 示例。

    • 概念:将一个多参数函数转换成一系列单参数函数。

    • 示例

      javascript
      const curry = fn => (...args) =>
      args.length >= fn.length
        ? fn(...args)
        : (...nextArgs) => curry(fn)(...args, ...nextArgs);
      const add = (a, b) => a + b;
      const curriedAdd = curry(add);
      const result = curriedAdd(2, 3);
  8. 解释什么是函数组合,并给出 JavaScript 示例。

    • 概念:将多个函数组合成一个函数。

    • 示例

      javascript
      const compose = (f, g) => x => f(g(x));
      const toUpperCase = x => x.toUpperCase();
      const exclaim = x => x + '!';
      const shout = compose(exclaim, toUpperCase);
      const result = shout('hello');
  9. 解释什么是函数式编程,并给出 JavaScript 示例。

  10. 手写柯里化 (Currying)

javascript
/* curry函数柯里化.js */
export function curry(fn) {
  if (typeof fn !== 'function') {
    throw new TypeError('Expected a function');
  }
  const arity = fn.length;

  function curried(...args) {
    if (args.length >= arity) {
      return fn(...args);
    } else {
      return function (...nextArgs) {
        return curried(...args, ...nextArgs);
      };
    }
  }
  return curried;
}

// 示例
const multiply = (a, b, c) => a * b * c;
const curriedMultiply = curry(multiply);
console.log(curriedMultiply(2)(3)(4)); // 24
  1. 手写 Memoize 与 Compose
javascript
/* memoize和compose.js */

// Memoize (缓存)
export function memoize(fn) {
  const cache = new Map();
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      return cache.get(key);
    }
    const result = fn(...args);
    cache.set(key, result);
    return result;
  }
}

// Compose (组合)
export function compose(...fns) {
  return function(...args) {
    // reduceRight 实现从右向左执行
    // 注意:这里的简单实现假设第一个函数可以接收多个参数,后续函数接收单个参数
    // 或者 args 在这里被当作一个整体传递(这取决于具体实现预期)
    // 通常 compose: (...fns) => x => fns.reduceRight((acc, f) => f(acc), x)
    return fns.reduceRight((acc, fn) => fn(acc), args);
  }
}
  1. 手写 call, apply, bind
javascript
/* 手写call、apply、bind.js */

// Call
Function.prototype.mycall = function (context, ...args) {
  if (typeof this !== 'function') {
    throw new TypeError('mycall must be called on a function')
  }
  context = context || globalThis
  const fnSymbol = Symbol()
  context[fnSymbol] = this
  const result = context[fnSymbol](...args)
  delete context[fnSymbol]
  return result
}

// Apply
Function.prototype.myapply = function (context, args) {
  if (typeof this !== 'function') {
    throw new TypeError('myapply must be called a function')
  }
  context = context || globalThis
  const fnSymbol = Symbol()
  context[fnSymbol] = this
  const result = Array.isArray(args) ? context[fnSymbol](...args) : context[fnSymbol]()
  delete context[fnSymbol]
  return result
}

// Bind
Function.prototype.mybind = function (context, ...args) {
  if (typeof this !== "function") {
    throw TypeError("myBind must be called on a function")
  }
  const self = this
  const boundFn = function (...newArgs) {
    // 处理 new 操作符的情况
    const isNew = this instanceof boundFn
    return self.apply(isNew ? this : context, args.concat(newArgs))
  }
  boundFn.prototype = Object.create(self.prototype)
  return boundFn
}
  1. 链式调用示例
javascript
/* 链式调用.js */
export class Chainable {
  constructor(value = 0) {
    this.value = value
  }
  add(val) {
    this.value += val
    return this
  }
  subtract(val) {
    this.value -= val
    return this
  }
  getValue() {
    return this.value
  }
}

const result = new Chainable(10).add(5).subtract(3).getValue()
console.log(result); // 12

MIT Licensed | Keep Learning.