「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2 万元奖池等你挑战」
背景
在今年一月份,很有幸参加了人生中的第一次阿里巴巴的面试,记忆尤新
在一面的时候,面试官没有过多的提问,一上来就是三道笔试题,一个小时完成
前两题是数组的题目,用了半个小时,就 A 出来了,当时写得挺爽,于是没有记录题目
在第三题,楼主就败北了,写了一半,就卡思路了,最后还是没能写完整 🙃。最后趁面试官不注意把问题记录一下了
这个题目在待办里边挂了整整半年,这几天花了挺多时间来研究这题,最后终于搞定,接下来就是原题目和我的解题过程(面对疾风吧!✨)
题目描述
实现一个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: 解题篇幅较长,希望大家耐心看完)
第一步:初步尝试🐱🏍
我们分析题目的第一个和第二个测试用例
1. EatMan('Hank')输出
Hi! This is Hank!
2. EatMan('Hank').eat('dinner').eat('supper')输出
Hi! This is Hank!
Eat dinner~
Eat supper~
思路分析
不难发现题目是想考察的是
- JavaScript 类的使用(为什么是类呢?因为我们可以把
eat这个方法看做是 EatMan 实例的一个属性) - 链式调用的实现
我们尝试写一写代码
代码实现
/*
* @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~
*/
进行一下测试
发现返回了我们想要的答案
是不是有点小成就感了 😀,那我们继续!
第二步:进阶🐱👓
分析第三个和第四个测试用例
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~
*/
发现输出结果和答案一致,那说明我们的改造是 OK 的
第三步:完善👏
最后,我们来实现eatFirst函数
思路分析
eatFirst函数有插队的功能,执行到了eatFirst之后,才能把该任务插入到任务队列的队头new MyEatMan()的时候不能立即执行任务队列,而是在任务进队完毕之后才执行- 每一个任务执行完毕的时候,触发下一个任务,保证任务的连续性
代码实现
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~
*/
// 测试用例4
EatMan('Hank').eat('dinner').eatFirst('lunch').eatFirst('breakfast')
/**
* 输出
* Eat breakfast~
* Eat lunch~
* Hi! This is Hank!
* Eat dinner~
*/
输出结果和答案完全一致!
大工告成了!
最后
关于面试,面试官大发慈悲,让我进入了二面,但是自己当时没有充分地准备,回答得不是很好,二面就挂掉了🤦♂️
希望大家看完这个文章都有所收获,如果能帮助屏幕前的你,解决了这个题目,那就最好不过了
我是970,好好学习不会差,大家一起进步!
最后的最后,求内推!地点深圳,希望大佬们积极留言啊!