13.3 高阶函数与闭包应用

高阶函数(Higher-Order Functions)

高阶函数是指至少满足下列条件之一的函数:

  1. 接受一个或多个函数作为参数
  2. 返回一个函数作为结果

基本概念

JavaScript中的高阶函数非常常见,例如数组的mapfilterreduce等都是高阶函数。

// 接受函数作为参数的高阶函数
function greet(name, formatter) {
  return `Hello, ${formatter(name)}!`;
}

function upperCaseName(name) {
  return name.toUpperCase();
}

console.log(greet('Alice', upperCaseName)); // "Hello, ALICE!"
// 返回函数的高阶函数
function createMultiplier(multiplier) {
  return function(x) {
    return x * multiplier;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15

常见的高阶函数模式

  1. 函数装饰器:增强函数功能而不改变其原始实现
function withLogging(fn) {
  return function(...args) {
    console.log(`Calling function with args: ${args}`);
    const result = fn(...args);
    console.log(`Function returned: ${result}`);
    return result;
  };
}

function add(a, b) {
  return a + b;
}

const addWithLogging = withLogging(add);
console.log(addWithLogging(2, 3));
// Calling function with args: 2,3
// Function returned: 5
// 5
  1. 条件执行函数
function unless(test, then) {
  if (!test) then();
}

const isAdmin = false;
unless(isAdmin, () => {
  console.log('You are not authorized');
});
// "You are not authorized"
  1. 计时函数
function time(fn) {
  return function(...args) {
    console.time('Function execution time');
    const result = fn(...args);
    console.timeEnd('Function execution time');
    return result;
  };
}

const timedAdd = time(add);
timedAdd(1, 2);
// Function execution time: 0.123ms

闭包(Closures)

闭包是指函数能够记住并访问其词法作用域,即使函数在其词法作用域之外执行。

闭包的基本原理

function outer() {
  const outerVar = 'I am outside!';
  
  function inner() {
    console.log(outerVar); // 访问外部变量
  }
  
  return inner;
}

const myInner = outer();
myInner(); // "I am outside!"

闭包的常见应用

  1. 数据私有化
function createCounter() {
  let count = 0; // 私有变量
  
  return {
    increment() {
      count++;
      return count;
    },
    decrement() {
      count--;
      return count;
    },
    getCount() {
      return count;
    }
  };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.count); // undefined (无法直接访问)
  1. 函数工厂
function createGreeting(greeting) {
  return function(name) {
    return `${greeting}, ${name}!`;
  };
}

const sayHello = createGreeting('Hello');
const sayHi = createGreeting('Hi');

console.log(sayHello('Alice')); // "Hello, Alice!"
console.log(sayHi('Bob'));      // "Hi, Bob!"
  1. 记忆化(Memoization)
function memoize(fn) {
  const cache = {};
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache[key]) {
      console.log('Returning cached result');
      return cache[key];
    }
    console.log('Calculating result');
    const result = fn(...args);
    cache[key] = result;
    return result;
  };
}

function expensiveCalculation(n) {
  console.log('Performing expensive calculation');
  return n * 2;
}

const memoizedCalc = memoize(expensiveCalculation);
console.log(memoizedCalc(5)); // Performing expensive calculation → 10
console.log(memoizedCalc(5)); // Returning cached result → 10

高阶函数与闭包的结合应用

  1. 部分应用(Partial Application)
function partial(fn, ...presetArgs) {
  return function(...laterArgs) {
    return fn(...presetArgs, ...laterArgs);
  };
}

function addThreeThings(a, b, c) {
  return a + b + c;
}

const addTenToTwoThings = partial(addThreeThings, 10);
console.log(addTenToTwoThings(20, 30)); // 60 (10 + 20 + 30)
  1. 防抖(Debounce)
function debounce(fn, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

window.addEventListener('resize', debounce(() => {
  console.log('Window resized');
}, 300));
  1. 节流(Throttle)
function throttle(fn, interval) {
  let lastTime = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastTime >= interval) {
      fn.apply(this, args);
      lastTime = now;
    }
  };
}

window.addEventListener('scroll', throttle(() => {
  console.log('Scrolling');
}, 200));
  1. 中间件模式
function composeMiddleware(middlewares) {
  return function(context, next) {
    let index = -1;
    return dispatch(0);
    
    function dispatch(i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'));
      index = i;
      let fn = middlewares[i];
      if (i === middlewares.length) fn = next;
      if (!fn) return Promise.resolve();
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err);
      }
    }
  };
}

const middlewares = [
  async (ctx, next) => {
    console.log('Middleware 1 start');
    await next();
    console.log('Middleware 1 end');
  },
  async (ctx, next) => {
    console.log('Middleware 2 start');
    await next();
    console.log('Middleware 2 end');
  }
];

const run = composeMiddleware(middlewares);
run({}).then(() => console.log('All done'));
// Middleware 1 start
// Middleware 2 start
// Middleware 2 end
// Middleware 1 end
// All done

实际应用案例

  1. 权限控制
function withPermission(permission, fn) {
  return function(...args) {
    if (checkPermission(permission)) {
      return fn(...args);
    } else {
      throw new Error('Permission denied');
    }
  };
}

function checkPermission(permission) {
  // 模拟权限检查
  const userPermissions = ['read', 'write'];
  return userPermissions.includes(permission);
}

function deleteFile(filename) {
  console.log(`Deleting ${filename}`);
}

const secureDelete = withPermission('write', deleteFile);
secureDelete('important.txt'); // 如果有权限则执行
  1. 缓存API请求
function cachedApiCall(expireTime) {
  const cache = {};
  
  return async function(url) {
    const now = Date.now();
    
    if (cache[url] && now - cache[url].timestamp < expireTime) {
      console.log('Returning cached data');
      return cache[url].data;
    }
    
    console.log('Making fresh API call');
    const response = await fetch(url);
    const data = await response.json();
    cache[url] = { data, timestamp: now };
    return data;
  };
}

const cachedFetch = cachedApiCall(5000); // 5秒缓存
cachedFetch('https://api.example.com/data')
  .then(data => console.log(data));
  1. React高阶组件(HOC)
function withLoadingIndicator(WrappedComponent) {
  return function WithLoading(props) {
    const [loading, setLoading] = useState(true);
    const [data, setData] = useState(null);
    
    useEffect(() => {
      async function fetchData() {
        setLoading(true);
        const result = await props.fetchData();
        setData(result);
        setLoading(false);
      }
      fetchData();
    }, [props.fetchData]);
    
    return loading ? <div>Loading...</div> : <WrappedComponent data={data} {...props} />;
  };
}

function DataDisplay({ data }) {
  return <div>{JSON.stringify(data)}</div>;
}

const DataDisplayWithLoading = withLoadingIndicator(DataDisplay);

总结

高阶函数和闭包是JavaScript中极其强大的特性:

  1. 高阶函数

    • 使代码更加模块化和可复用
    • 支持函数组合和行为参数化
    • 是函数式编程的基础
  2. 闭包

    • 允许函数"记住"创建时的环境
    • 实现数据私有化和封装
    • 创建有状态的函数

两者的结合使用可以解决许多复杂的编程问题,如:

  • 创建装饰器、中间件
  • 实现缓存和记忆化
  • 控制函数执行频率(防抖/节流)
  • 构建模块化和可复用的代码结构

掌握这些概念将使你能够编写更加灵活、强大且易于维护的JavaScript代码。

#前端开发 分享于 2025-03-25

【 内容由 AI 共享,不代表本站观点,请谨慎参考 】