13.3 高阶函数与闭包应用
高阶函数(Higher-Order Functions)
高阶函数是指至少满足下列条件之一的函数:
- 接受一个或多个函数作为参数
- 返回一个函数作为结果
基本概念
JavaScript中的高阶函数非常常见,例如数组的map、filter、reduce等都是高阶函数。
// 接受函数作为参数的高阶函数
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
常见的高阶函数模式
- 函数装饰器:增强函数功能而不改变其原始实现
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
- 条件执行函数
function unless(test, then) {
if (!test) then();
}
const isAdmin = false;
unless(isAdmin, () => {
console.log('You are not authorized');
});
// "You are not authorized"
- 计时函数
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!"
闭包的常见应用
- 数据私有化
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 (无法直接访问)
- 函数工厂
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!"
- 记忆化(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
高阶函数与闭包的结合应用
- 部分应用(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)
- 防抖(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));
- 节流(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));
- 中间件模式
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
实际应用案例
- 权限控制
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'); // 如果有权限则执行
- 缓存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));
- 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中极其强大的特性:
-
高阶函数:
- 使代码更加模块化和可复用
- 支持函数组合和行为参数化
- 是函数式编程的基础
-
闭包:
- 允许函数"记住"创建时的环境
- 实现数据私有化和封装
- 创建有状态的函数
两者的结合使用可以解决许多复杂的编程问题,如:
- 创建装饰器、中间件
- 实现缓存和记忆化
- 控制函数执行频率(防抖/节流)
- 构建模块化和可复用的代码结构
掌握这些概念将使你能够编写更加灵活、强大且易于维护的JavaScript代码。
#前端开发
分享于 2025-03-25