阿里面试题:实现一个EatMan。我没写出来🤦♂️

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2 万元奖池等你挑战javascript

背景

在今年一月份,颇有幸参加了人生中的第一次阿里巴巴的面试,记忆尤新前端

在一面的时候,面试官没有过多的提问,一上来就是三道笔试题,一个小时完成java

前两题是数组的题目,用了半个小时,就 A 出来了,当时写得挺爽,因而没有记录题目web

在第三题,楼主就败北了,写了一半,就卡思路了,最后仍是没能写完整 🙃。最后趁面试官不注意把问题记录一下了面试

这个题目在待办里边挂了整整半年,这几天花了挺多时间来研究这题,最后终于搞定,接下来就是原题目和个人解题过程(面对疾风吧!✨)后端

题目描述

实现一个EatMan
说明:实现一个EatMan,EatMan能够有如下一些行为
示例:
   1. EatMan('Hank')输出:
    Hi! This is Hank!
   2. EatMan('Hank').eat('dinner').eat('supper')输出
    Hi! This is Hank!
    Eat dinner~
    Eat supper~
   3. EatMan('Hank').eat('dinner').eatFirst('lunch')输出
    Eat lunch~
    Hi! This is Hank!
    Eat dinner~
   4. EatMan('Hank').eat('dinner').eatFirst('lunch').eatFirst('breakfast')输出
    Eat breakfast~
    Eat lunch~
    Hi! This is Hank!
    Eat dinner~
复制代码

思路分析和手撕代码

(ps: 解题篇幅较长,但愿你们耐心看完)数组

第一步:初步尝试🐱‍🏍

咱们分析题目的第一个和第二个测试用例markdown

1. EatMan('Hank')输出
   Hi! This is Hank!
 2. EatMan('Hank').eat('dinner').eat('supper')输出
   Hi! This is Hank!
   Eat dinner~
   Eat supper~
复制代码

思路分析app

不难发现题目是想考察的是函数

  1. JavaScript 类的使用(为何是类呢?由于咱们能够把 eat这个方法看作是 EatMan 实例的一个属性)
  2. 链式调用的实现

咱们尝试写一写代码

代码实现

/* * @Date: 2021-07-15 13:49:04 * @LastEditors: cunhang_wwei * @LastEditTime: 2021-07-15 14:08:34 * @Description: eatMan的初步尝试 */

class MyEatMan {
    constructor(name) {
        this.name = name

        this.printName(this.name)
    }

    // 打印名字
    printName(name) {
        console.log(`Hi! This is ${name}!`)
    }

    eat(thing) {
        console.log(`Eat ${thing}~`)
        // 返回 this 传递指针实现链式调用
        return this
    }
}

// 实例化
function EatMan(name) {
    return new MyEatMan(name)
}
复制代码
// 测试用例1
EatMan('Hank')
/** * 输出 * Hi! This is Hank! */

// 测试用例2
EatMan('Hank').eat('dinner').eat('supper')
/** * 输出 * Hi! This is Hank! * Eat dinner~ * Eat supper~ */
复制代码

进行一下测试

image.png

image.png

发现返回了咱们想要的答案

是否是有点小成就感了 😀,那咱们继续!

第二步:进阶🐱‍👓

分析第三个和第四个测试用例

3. EatMan('Hank').eat('dinner').eatFirst('lunch')输出
    Eat lunch~
    Hi! This is Hank!
    Eat dinner~
  4. EatMan('Hank').eat('dinner').eatFirst('lunch').eatFirst('breakfast')输出
    Eat breakfast~
    Eat lunch~
    Hi! This is Hank!
    Eat dinner~
复制代码

思路分析

咱们发现题目有了一个很大的改变,eatFirst会改变函数执行的顺序

有经验的大佬们一看到顺序,立马就悟了

对~ 考察的就是任务队列的知识

楼主以前就是在这个地方卡了思路,最后没有作出来 😅

咱们得对咱们第一步写的代码进行一个大改造,那就是增长任务队列

代码实现

class MyEatMan {
    constructor(name) {
        this.name = name
        // 任务队列,将须要执行的函数入队
        this.tasks = []
        // 第一个任务
        const task = this.printName(this.name)
        // 放入任务队列
        this.tasks.push(task)
        // 执行
        this.run()
    }

    // 打印名字
    printName(name) {
        return function() {
            console.log(`Hi! This is ${name}!`)
        }
    }

    // eat函数,每次调用都入队一个任务
    eat(thing) {
        const task = function() {
            console.log(`Eat ${thing}~`)
        }

        this.tasks.push(task)
        this.run()
        return this
    }

    // run执行任务
    run() {
        // 出队
        const currTask = this.tasks.shift()
        // 执行
        currTask && currTask()
    }
}
复制代码

进行一下测试

// 测试用例1
EatMan('Hank')
/** * 输出 * Hi! This is Hank! */
复制代码
// 测试用例2
EatMan('Hank').eat('dinner').eat('supper')
/** * 输出 * Hi! This is Hank! * Eat dinner~ * Eat supper~ */
复制代码

image.png

发现输出结果和答案一致,那说明咱们的改造是 OK 的

第三步:完善👏

最后,咱们来实现eatFirst函数

思路分析

  1. eatFirst函数有插队的功能,执行到了eatFirst以后,才能把该任务插入到任务队列的队头
  2. new MyEatMan() 的时候不能当即执行任务队列,而是在任务进队完毕以后才执行
  3. 每个任务执行完毕的时候,触发下一个任务,保证任务的连续性

代码实现

class MyEatMan {
    constructor(name) {
        this.name = name
        // 任务队列,将须要执行的函数入队
        this.tasks = []
        // 第一个任务
        const task = this.printName(this.name)
        // 放入任务队列
        this.tasks.push(task)
        // 为了保证任务都能在进队完毕以后再执行,建立一个宏任务,让执行任务的时机放到 下一个事件循环里
        let self = this
        setTimeout(function () {
            // console.log('tasks', self.tasks)
            self.run()
        }, 0)
    }

    // 打印名字
    printName(name) {
        let self = this
        return function () {
            console.log(`Hi! This is ${name}!`)
            self.run()
        }
    }

    // eat函数,每次调用都入队一个任务,并且还能实现链式调用
    eat(thing) {
        let self = this
        const task = function () {
            console.log(`Eat ${thing}~`)
            self.run()
        }

        this.tasks.push(task)
        return this
    }

    // eatFirst函数,谁最后初始化,谁先执行,并且还能实现链式调用
    eatFirst(thing) {
        let self = this
        const task = function () {
            console.log(`Eat ${thing}~`)
            self.run()
        }

        // 插入到队列的头部
        this.tasks.unshift(task)
        return this
    }

    // run执行任务
    run() {
        // 出队
        const currTask = this.tasks.shift()
        // 执行
        currTask && currTask()
    }
}


function EatMan(name) {
    return new MyEatMan(name)
}
复制代码

咱们使用测试用例进行测试

// 测试用例3

EatMan('Hank').eat('dinner').eatFirst('lunch')
/** * 输出 * Eat lunch~ * Hi! This is Hank! * Eat dinner~ */
复制代码

image.png

// 测试用例4
EatMan('Hank').eat('dinner').eatFirst('lunch').eatFirst('breakfast')
/** * 输出 * Eat breakfast~ * Eat lunch~ * Hi! This is Hank! * Eat dinner~ */
复制代码

image.png

输出结果和答案彻底一致!

大工告成了!

最后

关于面试,面试官大发慈悲,让我进入了二面,可是本身当时没有充分地准备,回答得不是很好,二面就挂掉了🤦‍♂️

但愿你们看完这个文章都有所收获,若是能帮助屏幕前的你,解决了这个题目,那就最好不过了

我是970,好好学习不会差,你们一块儿进步!

最后的最后,求内推!地点深圳,但愿大佬们积极留言啊!

相关文章
相关标签/搜索