JavaScript惰性求值场景为什么推荐使用箭头函数?
注意:其他不少编程语言都有惰性求值、延迟计算的机制,它们也将这类机制命名为「promises」,比如Scheme。而JavaScript中的Promise代表已经在执行的进程,可通过回调函数链式调用。如果你想要对表达式进行惰性求值,推荐使用无参数箭头函数:通过 f = () => 表达式 的形式创建惰性求值表达式,调用f()即可触发求值。
为什么MDN优先推荐箭头函数做惰性求值?
你给出的无上下文依赖的简单场景下,普通函数和箭头函数的运行效果确实完全一致,MDN的推荐是基于工程实践层面的优势,核心有三点:
- 语法更简洁,适配惰性求值的高频使用场景
惰性求值大多用来包装短的计算表达式,箭头函数省去了function关键字、return声明(单表达式隐式返回),代码可读性更高,核心逻辑一目了然:// 箭头函数写法 const lazyTotal = () => userInfo.shoppingCart.items.reduce(sumCalc, 0) // 普通函数写法冗余度明显更高 const lazyTotal = function() { return userInfo.shoppingCart.items.reduce(sumCalc, 0) } - 无独立this绑定,避免上下文丢失问题
这是最核心的优势,业务场景中的惰性计算逻辑往往依赖当前作用域的this,箭头函数会继承定义时所在作用域的this,不需要额外绑定就可以正常运行:
如果要用普通函数实现相同效果,你需要额外做class Order { discount = 0.8 originPrice = 100 // 箭头函数惰性求值,this永远指向类实例 lazyFinalPrice = () => this.originPrice * this.discount // 普通函数的this会随调用方式变化,取出单独调用时会丢失上下文 normalLazyPrice = function() { return this.originPrice * this.discount } } const order = new Order() // 把惰性函数取出到外部调用 const getPrice = order.lazyFinalPrice console.log(getPrice()) // 正常输出80 const getPriceNormal = order.normalLazyPrice console.log(getPriceNormal()) // 运行报错,this为undefinedbind绑定,会多出冗余代码。 - 天生避免误用
箭头函数不能作为构造函数调用,也没有prototype、arguments这些惰性求值场景完全用不到的特性,刚好匹配惰性求值函数「仅用于调用取值」的定位,不会出现误调用new导致的奇怪bug。
关于缓存的补充说明
你提到的箭头函数没有内置缓存特性是完全正确的,MDN的推荐仅仅是针对「触发执行前不计算」这个基础的惰性求值要求。如果你需要计算后缓存结果的能力,可以自己封装一个简易的memo工具函数来包装箭头函数即可:
const memoizeLazy = (fn) => { let cached = null let isComputed = false return () => { if (!isComputed) { cached = fn() isComputed = true } return cached } } // 带缓存的惰性求值函数 const lazyWithCache = memoizeLazy(() => 2 * 3)
内容的提问来源于stack exchange,提问作者Ahmed Ibrahim
相关产品推荐
相关产品推荐

