• 函数sum(1)(2)(3)(4)...(n)实现无限累加


    一开始看到这个题目我最先想到了闭包,

    可能会这么写:

    function sum(a){
        return function(b){
            return function(c){
                return function(d){
                    ......
                }
            }
        }
    }

    或许也会这么写:

    let sum = a => b => c => d => ... => a+b+c+d+...+n

    但是不论是以上哪种方式,都需要先固定参数个数,因此这两种写法都不可取

    解决办法——递归调用

    方法一:使用toString打印

    思路:当我们直接对函数使用 alert() 或 console.log() 时,函数的 toString() 方法会被调用。注意,valueOf方法会把数据类型转换成原始类型,toString方法会把数据类型转换成string类型,如果是对象会返回,toString() 返回 “[object type]”,其中type是对象类型。正常情况下,优先调用toString()。有运算操作符的情况下,valueOf()的优先级高于toString(),当调用valueOf()方法无法运算后还是会再调用toString()方法

    代码:

    function sum(a){
        let temp = function(b){
            return sum(a+b)
        }
        // temp.toString这里写成temp.valueOf也可以
        temp.toString = function(){
            return a
        }
        return temp
    }
    
    let ans = sum(1)(2)(3)
    console.log(ans)

    执行过程:这sum函数可以无限次循环调用,并且把所有传进去的值相加,最后返回所有值得总和。

      ①执行sum(1),此时a=1,返回temp函数

      ②执行temp(2),这个函数内执行sum(a+b),即sum(a+b)=sum(1+2)=sum(3),此时a=3,并且返回temp函数

      ③执行temp(3),这个函数内执行sum(a+b),即sum(a+b)=sum(3+3)=sum(6),此时m=6,并且返回temp函数

      ④后面没有传入参数,等于返回的temp函数不被执行而是打印。代码中的temp.toString的重写只是为了函数不执行时能够返回最后运算的结果值,这里即为6

    方法二:函数柯里化

    思路:也是用到toString打印,但是这里用到了函数式编程的思想,这里的sum(1)(2)(3)(4)...(n)等价于sum(1)(2,3)(4)...(n),也等价于sum(1,2,3)(4)...(n)等多种排列组合

    代码:

    let sum = 0
    function add (...args) {
        for(let i=0;i<args.length;i++){
            sum = sum + args[i] 
        }
        return sum
    }
    
    function currying (fn) {
        let val = null
        let temp = function(...newArgs) {
            val = fn.apply(this, newArgs)
            return temp
        }
        temp.toString = function(){
            sum = 0
            return val
        }
        return temp
    }
    
    let addCurry = currying(add)
    console.log(addCurry(1)(2)(3)(4, 5)) //15  这里是函数值为15,本质是函数字符串值
    console.log(addCurry(1)(2)(3, 4, 5)) //15
    console.log(addCurry(1, 2)(3, 4, 5)) //15

    补充:

      ①函数柯里化就是只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。简单来说,就是每次调用函数时,它只接受一部分参数,并返回一个函数,直到传递所有参数为止

      ②toString返回的是函数字符串值,后期可以通过Number函数将函数字符串值转换为数值

    扩展:求sum(1)(2)(3)...(n)()

    方法一:

    代码:

    function sum(a){
        return function(b){
            if(b!==undefined){ 
                return sum(a+b)
            }else{
                return a
            }
        }
    }
    
    let ans = sum(1)(2)(3)()
    console.log(ans)

    方法二——函数柯里化

    代码:

    function add (...args) {
        //求和
        return args.reduce((a, b) => a + b)
    }
    
    function currying (fn) {
        let args = []
        return function temp (...newArgs) {
            if (newArgs.length) {
                args = [
                    ...args,
                    ...newArgs
                ]
                return temp
            } else {
                let val = fn.apply(this, args)
                args = [] //保证再次调用时清空
                return val
            }
        }
    }
    
    let addCurry = currying(add)
    // 注意调用方式的变化
    console.log(addCurry(1)(2)(3)(4, 5)())  //15
    console.log(addCurry(1)(2)(3, 4, 5)())  //15
    console.log(addCurry(1)(2, 3, 4, 5)())  //15

    参考:

    https://juejin.im/post/5e6ed0bc6fb9a07c8334f75c

    https://juejin.im/post/5e40b566e51d4526ea7ee623

  • 相关阅读:
    JavaScript的学习----2.操作BOM对象
    Maven的配置和Eclipse中导入SpringBoot项目一些注意点
    JavaScript学习----1.基础篇
    线程池的学习
    CSS的初步学习
    类的加载细节探索
    反射与注解
    数据结构第二章
    数据结构第一章
    用结构和STL常用算法实现对学生成绩的排序和查找(vector)
  • 原文地址:https://www.cnblogs.com/FHC1994/p/12777417.html
Copyright © 2020-2023  润新知