阿里面試題:實現一個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,好好學習不會差,你們一塊兒進步!

最後的最後,求內推!地點深圳,但願大佬們積極留言啊!

相關文章
相關標籤/搜索