面试题之抽象组合函数🤔🤔

JS编程题

函数组合基础

首先,我们拥有了一个基本的字符串处理函数toUpperCase,用于将输入的字符串转换为大写形式。此外,还有一个字符串拼接函数hellow,它接受一个字符串参数并返回"Hello World!"加上该字符串的结果。

js 复制代码
var toUpperCase = function(x) {
    return x.toUpperCase();
}


var hellow = function(x) {
    return "Hello World!"+x;
}

简单组合

思考如何组合toUpperCase和hellow实现greet函数,能将输入的字符大写并且拼接上"Hello World!",这一步是不难想到的。

js 复制代码
 var greet = function(x) {
 return hellow(toUpperCase(x));
}

如何又出现一个toLowerCase函数,有着将字符转为小写的功能,我们是不是要向下面这样再写一次?

js 复制代码
var toLowerCase = function(x) {
    return x.toLowerCase();
}

var greet2=function(x){
    return hellow(toLowerCase(x));
}

这样我们才能将新的功能耦合起来,思考思考是不是有些许麻烦,我们能不能做到封装一个函数,它能够 组合抽象函数 C=A(B(x)),有了思路,代码自然就形成了。

手写compose 组合函数

js 复制代码
var compose = function(f,g) {
    // 闭包
    return function(x) {
        return f(g(x));
    }
}

var greet = compose(hellow,toUpperCase);
console.log(greet('kevin'));

通过 compose 函数,你可以轻松地将多个函数组合成一个新的函数,并按照从右到左的顺序依次应用这些函数。这种方式不仅提高了代码的可读性和复用性,还使得复杂的操作可以通过简单的函数组合来实现。

完成这一步,你是不是觉得面试题已经解完了呢?但是,若你深入思考,我们只解决了,两个函数的组合,如果存在三个四个,乃至更多,我们该如何解决呢?

最终成品

js 复制代码
var compose = function() {
    var args = arguments; // 获取所有传入的函数
    var start = args.length - 1; // 最右边的函数索引,即最先执行的函数

    return function(x) { // 返回一个新函数,该函数接受一个参数 x
        var i = start;
        var result = args[start].call(this, x); // 先执行最右边的函数

        while (i--) { // 从右向左依次调用其他函数
            result = args[i].call(this, result); // 将上一个结果作为参数传递给下一个函数
        }

        return result; // 返回最终的结果
    }
}

var greet = compose(hellow, toUpperCase); // 组合 hellow 和 toUpperCase 函数
console.log(greet('kevin')); // 输出: Hello World!KEVIN
  1. 定义 compose 函数:

    • compose 函数不直接接受两个函数作为参数,而是使用 arguments 对象来接收任意数量的函数。
    • args 变量保存了所有传入的函数。
    • start 变量表示最右边(即最先执行)的函数在 args 数组中的索引。
  2. 返回一个新的匿名函数:

    • 这个匿名函数接受一个参数 x,它将作为第一个输入值传递给最右边的函数。
    • i = start 初始化循环变量 i,使其指向最右边的函数。
    • result = args[start].call(this, x) 首先调用最右边的函数,并将结果存储在 result 中。
  3. 循环调用其他函数:

    • 使用 while (i--) 循环从右向左依次调用每个函数。
    • 在每次迭代中,当前的 result 作为参数传递给下一个函数(即左边的函数),并将新的结果重新赋值给 result。
    • args[i].call(this, result) 确保每个函数都能正确访问当前的执行上下文(即 this 值)。

若不了解call 的用法可以看看除了 call,JS 还有哪些强大的函数绑定方式?探索 JavaScript 函数绑定的多样世界 在我深入研究 setT - 掘金

this 在此处的作用:

  • 如果这些函数是普通函数(即没有依赖于 this),那么 this 的值不会影响函数的行为。
  • 如果这些函数是对象的方法,并且它们内部依赖于 this,那么通过 call(this, ...) 可以确保 this 正确指向调用上下文中的对象。

前序遍历二叉树的又一写法

补充点与抽象组合函数无关的面试题,想要编写二叉树的前序遍历,你第一想到的肯定是递归,代码也很简洁:

js 复制代码
function preorderTraversal(root) {
     if(!root) return 
     console.log(root.val)
     preorderTraversal(root.left)
     preorderTraversal(root.right)
}

如果面试官,让你不能用递归,使用迭代的写法,你是否还会觉得简单呢? 想到迭代实现二叉树,能否想到一个数据结构,栈的用法,先进后出,来模拟二叉树的遍历

js 复制代码
function preOrderTraversal(root){

    if(!root) return 
    //  栈模拟递归
    var stack = []
    stack.push(root)
    while(stack.length){
        var node = stack.pop()
        console.log(node.val)
      
  // 注意:先压入右子节点,再压入左子节点,以保证左子节点先被处理
        if(node.right) stack.push(node.right)
        if(node.left) stack.push(node.left)
    }
}

重点:

看到该题首先你有没有想到使用栈去实现,其次是:根据栈的先进后出,有没有先压入右子树,再压入左子树,为关键点。

相关推荐
怕浪猫1 小时前
GEO 优化到底是什么?AI时代内容创作者必须懂的新技能
算法·面试·github
朝朝辞暮i2 小时前
C++ 第 23 课:class —— 开始真正进入面向对象
开发语言·c++·算法
Evand J2 小时前
【MATLAB例程】三维RRT+APF避障路径规划与到达角(AOA)定位算法|三维路径优化与定位仿真例程
算法·matlab·路径规划·代码·定位·rrt·aoa
weixin_307779134 小时前
有限产能智能排产与动态重排智能体:从需求解构到技术实现
开发语言·人工智能·算法·架构
朝朝辞暮i4 小时前
C++ 第 27 课:智能指针 shared_ptr
开发语言·c++·算法
沙漠之主4 小时前
C++编程教学设计资料:从入门到实战的完整课程方案
java·前端·c++
hasty4 小时前
不上传新包,也能改变用户拿到的版本:npm dist-tag 的 OIDC 权限治理
前端·npm·node.js
朝朝辞暮i5 小时前
C++ 第 29 课:回调函数 Callback
开发语言·c++·算法
Godspeed Zhao5 小时前
现代智能雷达技术14——算法(0)
线性代数·算法·雷达
Csvn5 小时前
diff 算法(虚拟 DOM Reconciliation)
前端