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)
        }
    }
}

总结:

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

相关推荐
T___T17 分钟前
Ajax 数据请求详解与实战
javascript·面试
冴羽31 分钟前
能让 GitHub 删除泄露的苹果源码还有 8000 多个相关仓库的 DMCA 是什么?
前端·javascript·react.js
悟能不能悟33 分钟前
jsp怎么拿到url参数
java·前端·javascript
程序猿_极客1 小时前
JavaScript 的 Web APIs 入门到实战全总结(day7):从数据处理到交互落地的全链路实战(附实战案例代码)
开发语言·前端·javascript·交互·web apis 入门到实战
一枚前端小能手1 小时前
2618. 检查是否是类的对象实例(JavaScript)
前端·javascript
小蹦跶儿2 小时前
解决Webpack 打包报错:TypeError: Cannot assign to read only property 'exports' ?
javascript·vue.js·webpack
小飞大王6662 小时前
JavaScript基础知识总结(四):常见内置构造函数,正则表达式,作用域与闭包
前端·javascript·正则表达式
3秒一个大2 小时前
Ajax 数据请求详解:从概念到实战
javascript
Pu_Nine_93 小时前
Vue 3 项目 ESLint 配置详解:初始模板的正确配置
前端·javascript·vue.js
im_AMBER3 小时前
HTTP概述 01
javascript·网络·笔记·网络协议·学习·http