js高级解法:记忆函数优化两数相加和递归(内含伪数组Arguments)

前言:

在日常的JavaScript编程中,经常会遇到需要计算两个数的和的场景。虽然最简单直接的方法是使用加法运算符直接相加,但对于大量重复计算的情况,这种方法可能会导致性能问题。为了解决这个问题,我们可以使用记忆函数来优化计算过程,避免重复计算,提高代码的执行效率。

记忆函数的原理:

记忆函数是一种将函数的计算结果缓存起来的技术。当函数被调用时,它首先检查之前是否已经计算过相同的输入,并将结果返回,而不是重新计算。这样可以避免重复计算,提高函数的执行效率。

记忆函数的实现:

在JavaScript中,我们可以使用闭包来实现记忆函数。具体步骤如下:

  1. 创建一个空对象,用于存储计算结果的缓存。
  2. 创建一个闭包函数,该函数接受两个参数作为输入。
  3. 在闭包函数内部,首先检查缓存对象中是否已经存在相同的输入作为键的计算结果。如果存在,则直接返回缓存中的结果。
  4. 如果缓存中不存在该输入的计算结果,则进行实际的计算,并将结果存储在缓存对象中。
  5. 最后,返回计算结果。

伪数组 Arguments

伪数组(pseudo-array)是指具有类似数组特性的对象,但不是真正的数组。JavaScript中的arguments就是一个典型的伪数组。arguments对象是在函数内部自动创建的特殊对象,用于存储函数被调用时传入的所有实参(即形参对应的实际值)。arguments对象中包含一个类数组的结构,存储了这些实参,并且可以通过下标访问它们。下面是关于arguments伪数组的一些说明:

  1. Object.prototype.toString.call(arguments)可以用来检测一个对象是否为伪数组。对于arguments对象,它返回的结果是'[object Arguments]'

  2. arguments对象具有length属性,这意味着我们可以像数组一样使用下标访问arguments中的元素。例如,arguments[0]表示获取arguments中的第一个参数。

  3. 由于arguments不是真正的数组,所以它没有数组的常用方法,如join()slice()等。如果我们希望将arguments转换为真正的数组,可以使用以下几种方法进行转换:

    • Array.from(arguments):通过Array.from()方法将arguments转换为真正的数组。
    • [...arguments]:使用扩展运算符将arguments转换为数组。 这两种方法都会创建一个新的数组,其中包含与arguments相同的元素。
  4. 如果我们只需要临时使用数组的某个方法,而不希望创建新的数组,可以使用Array.prototype.join.call(arguments, '--')这样的方式。这将调用Array原型上的join()方法,并将arguments作为函数的上下文对象,从而实现了在arguments上调用join()方法。

需要注意的是,伪数组是永久存在的,而通过转换得到的真正数组是临时的,只在转换后的代码段中有效。因此,在使用伪数组时,我们需要根据具体情况选择适当的处理方式。

记忆函数的示例:

记忆函数优化两数相加:

javascript 复制代码
function sum(a, b){
    if(arguments.length !== 2){  
        throw new Error('参数有误')
    }
    if(typeof a !== 'number' || typeof b !== 'number'){
        throw new Error('必须是整数')
    }
    return a + b
}

// 记忆函数 
function memorize(f){
    if(typeof f !== 'function') return 
    var cache = {}  // 空间换时间   cache 自由变量(不会被销毁,永远存在)
    return function (){
        var key = arguments.length + Array.prototype.join.call(arguments, ',')
        if(key in cache){
            return cache[key]
        }else{
            return cache[key] = f.apply(this, arguments)
        }
    }
}

const memoizedSum = memorize(sum)
console.log(memoizedSum(1, 2));    // 第一次计算,输出 3
console.log(memoizedSum(1, 2));    // 直接从缓存中获取,输出 3
console.log(memoizedSum(4, 6));     // 新的输入,计算并存入缓存,输出 10
console.log(memoizedSum(4, 6));     // 直接从缓存中获取,输出 10

在上面的代码中,我们使用memoizedSum函数来计算两数相加的结果。通过将计算结果存储在缓存中,当函数再次调用时,可以直接从缓存中取出结果,避免了重复计算。

记忆函数优化递归(斐波那契数列):

javascript 复制代码
var fibonacci = function(n){    // 暴击破解法
    return n < 2? n : fibonacci(n - 1) + fibonacci(n - 2)
}
function memorize(f){   // 记忆函数法
    if(typeof f !== 'function') return 
    var cache = {}  // 空间换时间   自由变量(不会被销毁,永远存在)
    return function (){
        var key = arguments.length + Array.prototype.join.call(arguments, ',')
        if(key in cache){
            return cache[key]
        }else{
            return cache[key] = f.apply(this, arguments)
        }
    }
}

总结:

记忆函数是一种优化计算过程的技术,通过将函数的计算结果缓存起来,避免重复计算,提高代码的执行效率。然而,在实际使用中,我们也需要注意记忆函数的适用性和限制。对于输入空间较大的问题,缓存可能会导致内存占用过大,甚至造成内存溢出。因此,在使用记忆函数时,需要权衡利弊,并根据具体情况进行选择和优化。

相关推荐
程序猿阿伟9 分钟前
《虚拟即真实:数字人驱动技术在React Native社交中的涅槃》
javascript·react native·react.js
C+ 安口木35 分钟前
纯前端实现图文识别 OCR
前端·javascript·ocr
勇敢*牛牛1 小时前
SVG 与 Canvas 技术调研对比
javascript
NoneCoder1 小时前
正则表达式与文本处理的艺术
前端·javascript·面试·正则表达式
海盐泡泡龟3 小时前
Javascript本地存储的方式有哪些?区别及应用场景?(含Deep Seek讲解)
开发语言·javascript·ecmascript
John_ToDebug4 小时前
Chromium 回调设计实战:BindOnce 与 BindRepeating 的最佳实践
c++·chrome·性能优化
Elastic 中国社区官方博客5 小时前
JavaScript 中使用 Elasticsearch 的正确方式,第一部分
大数据·开发语言·javascript·数据库·elasticsearch·搜索引擎·全文检索
万物得其道者成5 小时前
从零开始创建一个 Next.js 项目并实现一个 TodoList 示例
开发语言·javascript·ecmascript
vvilkim5 小时前
深度解析:Redis 性能优化全方位指南
数据库·redis·性能优化
sunbyte6 小时前
50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Expanding Cards (展开式卡片)
javascript·vue.js·ecmascript