惰性函数是一种函数式编程技巧,它通过在首次调用时动态重写自身,避免后续调用中的重复条件判断,从而提高执行效率。这种技术特别适用于需要环境检测或初始化配置的场景,如浏览器特性检测、API兼容性处理等。
工作原理
- 首次调用时执行判断:函数首次运行时进行必要的条件检测
- 函数重写:根据检测结果重写函数自身
- 返回适当的实现:返回符合当前环境的实现
- 后续调用直接使用优化版本:避免重复判断,提高性能
适用场景
- 浏览器特性检测和兼容性处理
- 只需执行一次的初始化操作
- API适配器模式实现
- 配置参数的一次性处理
🌰 示例
初始版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| function createXHR() { var xhr = null
if (typeof window['XMLHttpRequest'] !== undefined) { xhr = new XMLHttpRequest()
createXHR = function () { return new XMLHttpRequest() } } else { xhr = new ActiveXObject('Microsoft.XMLHTTP')
createXHR = function () { return new ActiveXObject('Microsoft.XMLHTTP') } }
return xhr }
|
优化后版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function createXHR() { let xhr
if (typeof XMLHttpRequest !== 'undefined') { createXHR = function () { return new XMLHttpRequest() } } else if (typeof ActiveXObject !== 'undefined') { createXHR = function () { return new ActiveXObject('Microsoft.XMLHTTP') } } else { createXHR = function () { throw new Error('当前浏览器不支持XMLHttpRequest') } }
return createXHR() }
|
🌰 拓展应用
1. 事件绑定兼容性处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function addEvent(element, type, handler) { if (element.addEventListener) { addEvent = function (element, type, handler) { element.addEventListener(type, handler, false) } } else if (element.attachEvent) { addEvent = function (element, type, handler) { element.attachEvent('on' + type, handler) } } else { addEvent = function (element, type, handler) { element['on' + type] = handler } }
return addEvent(element, type, handler) }
|
2. 缓存计算结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function fibonacci(n) { const cache = {}
function calculateFib(num) { if (cache[num]) return cache[num]
if (num <= 1) return num
const result = calculateFib(num - 1) + calculateFib(num - 2) cache[num] = result return result }
return calculateFib(n) }
|
3. 配置参数处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| function createAPI(config) { const baseURL = config.baseURL || '' const timeout = config.timeout || 5000 const headers = config.headers || {}
createAPI = function (endpoint, options) { return fetch(`${baseURL}${endpoint}`, { timeout, headers: { ...headers, ...(options?.headers || {}) }, ...options, }) }
return createAPI }
const api = createAPI({ baseURL: 'https://api.example.com', timeout: 3000, headers: { 'Content-Type': 'application/json' }, })
api('/users', { method: 'GET' })
|
性能考量
- 优点:避免重复条件判断,提高执行效率
- 缺点:首次调用性能略低,需要额外的函数重写操作
- 适用场景:调用频率高、判断条件复杂的场景
最佳实践
- 只在真正需要惰性处理的场景使用
- 确保重写后的函数逻辑与原函数一致
- 考虑添加错误处理机制
- 在需要多次调用的场景下使用,单次调用场景可能不值得