ToC
惰性函数是什么?
在了解惰性函数是什么之前,我们先看一个例子:
以上代码有什么问题吗?有没有优化空间?有,而且有两个。
- 全局污染(副作用)
- 每次都需要判断 timeStamp 是否有值
这就是而这就是惰性函数需要解决的问题。
它的好处是什么?
惰性函数的优点如上,它是为了解决全局污染和多次重复判断的问题而诞生的。查看以下示例,并思考它有什么问题:
以上代码存在的问题是获取的时间是声明时获取到的时间,而不是第一次执行 getTimeStamp
时获取到的时间。那么我们再对其进行改良一下:
以上代码在执行的时候在函数内部覆写了自身,使得在运行第一次后,下一次的执行都是修改后的结果,这样就可以绕过每次都需要判断的问题了,同时因为每次获取到的值都是已经确定的,往后的执行速度都会比第一次快,如果这个函数本身需要处理的逻辑很多的话,这个优势会更加明显。不过这样做对静态类型分析不太友好,比如 TypeScript,使用时需要进行一定的取舍。
实际应用
因为在一些版本比较久的浏览器中对 dom 元素的事件处理的方式是不统一的,如果想要兼容旧版本的浏览器时,我们就需要对其进行处理:
至于到底是使用立即执行函数还是惰性函数来优化程序,这取决于你。通常这适合于一些只取值一遍的方法与场景。
缓存函数(也叫函数记忆)(memorize)
在了解缓存之前,我们先看一个阶乘的例子:
在正常流程中,我们每次调用 factorial(6)
的时候都需要重新去计算一次 6 的阶乘的结果,这使得每次执行的时候会多出很多多余的消耗,而这部分的消耗是不必要的,因为结果已经出来了,就不需要再去重复进行求值取值了。同时,因为递归是反复调用自身的特性,这也会让函数本身的调用次数过多,导致程序的调用栈过深,而消耗大量性能资源。这时候我们可以使用缓存来优化这段程序。
从结果来看,执行次数减少了一半,这是因为如果已经计算过值的话,则不会再去递归调用函数来取值,所以达到了优化的目的。
缓存函数的封装
以上代码也不是一点问题没有,至少它在污染全局函数的方面上做了很大的 “贡献”。那我们可以对其进行封装。
可以看出差距算是比较明显的了。
以上。