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

总结:

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

相关推荐
假装我不帅14 分钟前
jquery-validation使用
前端·javascript·jquery
怕浪猫19 分钟前
React从入门到出门第六章 事件代理机制与原生事件协同
前端·javascript·react.js
天府之绝22 分钟前
uniapp 中使用uview表单验证时,自定义扩展的表单,在改变时无法触发表单验证处理;
开发语言·前端·javascript·vue.js·uni-app
局外人LZ34 分钟前
libsodium.js:web端与 Node.js 的现代加密工具集,构建前端安全加密体系
前端·javascript·node.js
xkxnq40 分钟前
第二阶段:Vue 组件化开发(第 20天)
前端·javascript·vue.js
哈__43 分钟前
React Native 鸿蒙跨平台开发:Keyboard 键盘控制
javascript·react native·react.js
lili-felicity44 分钟前
React Native 鸿蒙跨平台开发:TextInput 数据键盘实现与最大文字长度限制
javascript·react native·react.js·harmonyos
光影少年44 分钟前
electron通信方式有哪些?
前端·javascript·electron
meichaoWen1 小时前
【nodejs】nodejs的一些基础知识
开发语言·前端·javascript
@Autowire1 小时前
Grid-grid-template-areas 属性
前端·javascript·css