JavaScript学习笔记之函数记忆

网络安全 2025-04-20 10:57www.168986.cn网络安全知识

这篇文章将带你了解JavaScript中的函数记忆,特别是其在菲波那契数列实现中的应用。长沙网络推广为我们带来了这个有趣且实用的主题,现在就让我们一起来吧。

一、函数记忆的定义

函数记忆是一种技术,它通过将上一次的计算结果缓存起来,当下一次调用函数时,如果遇到相同的参数,就直接返回缓存中的数据,而无需重新计算。这种技术可以有效提高程序的运行效率。

二、一个简单的例子

假设我们有一个简单的加法函数:

function add(a, b) {

return a + b;

}

通过使用函数记忆技术,我们可以优化这个函数,使其在重复调用时能够更快地返回结果。具体来说,当第二次调用该函数并传入相同的参数时,函数将直接从缓存中返回结果,而不是重新计算。

三、函数记忆的原理

实现一个函数记忆功能很简单。其基本原理是:将参数和对应的结果数据存储在一个对象中。当再次调用函数时,判断参数是否已存在于缓存中,如果存在,就直接返回对应的结果数据。

四、示例代码及测试

下面是一个简单的函数记忆实现示例:

// 第一版实现(来自《JavaScript权威指南》)

function memoize(f) {

var cache = {};

return function(){

var key = arguments.length + Array.prototype.join.call(arguments, ","); // 这里使用join方法拼接参数可能会有问题,需要考虑更完善的解决方案

if (key in cache) {

return cache[key];

} else {

return cache[key] = f.apply(this, arguments); // 将计算结果存入缓存并返回结果

}

}

}

我们可以通过一个简单的测试来比较使用函数记忆和不使用函数记忆的性能差异。测试结果显示,在大量重复调用相同参数的情况下,使用函数记忆可以显著提高程序的运行效率。需要注意的是,并非所有情况下都适合使用函数记忆技术。在某些简单场景下,使用函数记忆可能会导致性能下降。在实际应用中需要根据具体情况进行权衡和选择。当参数是对象时,直接使用join方法拼接可能会产生问题,需要采取更合适的解决方案来生成唯一的key值。对于更复杂的数据类型或数据结构,我们需要更精细的设计缓存策略。函数记忆是一种有效的编程技巧,它可以提高程序的运行效率,尤其是在时间复杂度成为瓶颈的客户端JavaScript环境中。在大多数情况下,牺牲空间复杂度以换取时间复杂度是值得的。在未来的版本中,我们可以进一步优化缓存策略和数据结构以适应更广泛的场景和需求。让我们一起期待更多的和发现! memoization:从 demo 验证问题到实际应用场景

让我们通过一个简单的示例来 memoization 的工作原理。假设我们有一个函数 `propValue`,它返回对象的 `value` 属性值。为了优化性能,我们尝试使用 memoization 技术来缓存函数的执行结果。当我们在连续调用时遇到了问题,结果似乎并不符合预期。让我们深入研究一下这个问题,并看看 underscore 的 `memoize` 函数是如何实现的。

在 underscore 的 `memoize` 函数实现中,我们可以看到它默认使用函数的第一个参数作为缓存的 key 值。这在某些情况下可能并不适用,尤其是当函数有多个参数时。为了正确处理多个参数的情况,我们需要自定义 hash 函数,即传入一个 `hasher` 参数。这个 `hasher` 函数能够将函数的参数转换为一个字符串或哈希值作为缓存的 key 值。为了解决这个问题,我们可以使用 `JSON.stringify` 来将参数对象转换为字符串形式作为缓存的 key 值。这样,即使参数是对象,也可以将其正确地存储和检索。这种改进确保了当使用具有多个参数的函数进行 memoization 时,我们可以得到预期的结果。

那么,memoization 技术在哪些场景下可以应用呢?让我们以斐波那契数列为例来说明。在没有使用 memoization 的情况下,计算斐波那契数列的一个数值会导致大量的重复计算。这是因为斐波那契数列中的每个数字都依赖于前两个数字的计算结果,而在计算过程中,很多数字会被重复计算多次。如果我们使用 memoization 技术来缓存已经计算过的数字结果,就可以避免重复计算,从而提高性能。如果不使用 memoization,计算斐波那契数列中的某些数值(如第 40 个数字)可能会导致函数被调用数千次甚至更多次。memoization 在递归、重复函数调用等场景中非常有用,可以帮助我们提高程序的性能。你是否曾疑惑,为何在计算斐波那契数列时,函数调用次数会如此之多?让我们深入这一现象。

当我们执行 fib(0) 时,只需调用一次函数。随着数值的增大,调用的次数逐渐累积。例如,执行 fib(2) 时,需要计算 fib(1) 和 fib(0) 的结果,再加上本身的计算,共需三次调用。以此类推,执行 fib(10) 时,调用的次数竟高达 453 次!这是一个惊人的数字。

如果我们使用函数记忆技术,情况将大为不同。调用次数从 453 次骤降至 12 次!这是因为函数记忆技术能够存储之前计算过的结果,当再次需要同样的结果时,直接返回存储的值,避免了重复计算。

那么这 12 次调用是如何产生的呢?从 0 到 10 的结果各储存一遍应该是 11 次。实际上,多出来的那一次是因为在生成新的 fibonai 函数时,我们覆盖了原始的 fibonai 函数。当我们执行 fibonai(0) 时,执行一次函数并将 cache 设置为 {0: 0}。当我们执行 fibonai(2) 时,需要计算 fibonai(1) 和 fibonai(0),由于 cache 中已经有了 fibonai(0) 的结果(值为 0),因此会再次执行一次 fibonai 函数。多出来的那一次调用就在此处产生。

那么在实际开发中,为何我们需要关注这种场景呢?其实这是一个典型的示例,当有大量重复计算或者计算依赖于之前的结果时,函数记忆技术将大有裨益。虽然斐波那契数列的计算在日常开发中可能不常用到,但类似的场景在实际项目中是普遍存在的。当我们遇到这种场景时,就会明白函数记忆的价值所在。

函数记忆技术能够显著提高计算效率,减少重复计算。通过理解和应用这种技术,我们可以更好地优化代码性能,提高项目的整体效率。

Copyright © 2016-2025 www.168986.cn 狼蚁网络 版权所有 Power by