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

总结:

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

相关推荐
_乐无20 分钟前
Unity 性能优化方案
unity·性能优化·游戏引擎
Dread_lxy26 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与2 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
前端郭德纲2 小时前
浏览器是加载ES6模块的?
javascript·算法
JerryXZR2 小时前
JavaScript核心编程 - 原型链 作用域 与 执行上下文
开发语言·javascript·原型模式
帅帅哥的兜兜2 小时前
CSS:导航栏三角箭头
javascript·css3
渗透测试老鸟-九青2 小时前
通过投毒Bingbot索引挖掘必应中的存储型XSS
服务器·前端·javascript·安全·web安全·缓存·xss
龙猫蓝图2 小时前
vue el-date-picker 日期选择器禁用失效问题
前端·javascript·vue.js
夜色呦2 小时前
掌握ECMAScript模块化:构建高效JavaScript应用
前端·javascript·ecmascript