前言
之前看到一个有意思的题目,由于太懒,一直没有整理。最近不想玩游戏,抽空整理一下,小白自己瞎整活儿,有什么说的不对的,还请大家多多指导。
题目是酱紫的:
lazyMan.eat('Breakfest').sleep(4).eat('Launch').sleep(5).eat('Dinner')
代码执行后输出
my name is pig
I ate Breakfest
等待 4 s
I ate Launch
等待 5 s
I ate Dinner
第一步 分析功能
- 首先,
layman这家伙有eatsleep两个基本方法,并且这两个方法都是支持链式调用的。 - 其次,
lazyMan的sleep方法具有延时效果
第二步 整理思路
- 首先
lazyMan有sleepeat这些方法,基于面向对象的思想,我们可以通过一个类去实现它。 - 其次,这个家伙每次只能做一件事情,我们就用一个队列去接收他要做的事情,至于这个队列,我们可以放在数组中。
- 然后,
sleep具有延时效果,我们要使用延时器
第三步 基础代码
class LazyMan {
constructor(name) {
// 虽然 lazyMan 很懒,但我们依然给他一个名字
this.name = name
// 我们把 lazyMan 要做的事情放在一个数组里
this.queue = []
}
/**
* eat
* @param { String } what
* @return {*}
* @memberof LazyMan
*/
eat(what) {
// 返回 this 实现链式调用
return this
}
/**
* sleep
* @param { Number } hours
* @return {*}
* @memberof LazyMan
*/
sleep(hours) {
// 同样返回 this 实现链式调用
return this
}
}
这样一个基本的方法和属性就都有了,接下来就要考虑怎么去实现他的队列方法了。想了很久还是没有想到,没出息的我就去看别人的代码了, >_< 。(没办法,能力有限啊,靠自己不能做到,就要借巨人的肩膀用一下了)然后,真香!好了,看来很多大神的讲解,接下来我们用自己的话复述一下:
既然 eat sleep 都是行为,我们就用函数给他包裹起来,并把他们放到队列里。然后在封装一个 next 方法,从队列里面,把行为拿出来,执行一下。并且在函数执行完成后再调用一下这个next 方法,就能完成队列里的所有行为了,(好吧,其实就是递归执行)ok !开干!
第四步 功能实现
...
/**
* next
* @memberof LazyMan
*/
// 先封装一个 next 方法
next() {
// 把要执行的行为抽出来,并且执行一下
const fn = this.queue.shift()
fn && fn()
}
...
接下来,就是把行为一个个放进去了
...
/**
* eat
* @param { String } what
* @return {*}
* @memberof LazyMan
*/
eat(what) {
// eat 是一个行为 我们用函数把它包裹起来
let fn = (() => {
// 用一个闭包把吃了什么记录下来
return () => {
console.log(`I ate ${what} !`)
// 行为完成,调用 next 方法,执行下一个行为
this.next()
}
})(what)
this.queue.push(fn)
// 返回 this 实现链式调用
return this
}
/**
* sleep
* @param { Number } hours
* @return {*}
* @memberof LazyMan
*/
sleep(hours) {
const _this = this
let fn = (function () {
return function () {
setTimeout(function () {
console.log(`I slept ${hours} hours ... ...`)
// 同样地,行为完成,调用 next 方法,执行下一个行为
_this.next()
}, hours * 1000)
}
})(hours)
// 同样地,把 sleep 行为放到队列里
this.queue.push(fn)
// 同样返回 this 实现链式调用
return this
}
...
然后,就是这个队列要怎么执行的问题了
...
constructor(name) {
...
// 第一个行为
const fn = (() => {
return () => {
console.log(`My name is ${name}`)
// 开始执行第二个行为
this.next()
}
})()
this.queue.push(fn)
// 等实例化完成开始执行队列任务
setTimeout(() => {
this.next()
}, 0)
}
...
执行一下
const lazyman = new LazyMan('Pikky').eat('Breakfest')
lazyman.sleep(4)
lazyman.eat('Launch')
lazyman.sleep(5)
lazyman.eat('Dinner')
lazyman.sleep(8)
// My name is Pikky
// I ate Breakfest !
// I slept 4 hours ... ...
// I ate Launch !
// I slept 5 hours ... ...
// I ate Dinner !
// I slept 8 hours ... ...
// 完美👍👍👍
总结
其实这道题考的是一个 ① 队列的实现,以及 ② 链式调用的实现。开发的过程中,我们也用到了 ③ 事件轮询的机制和 ④ 闭包以及 ⑤ 递归、⑥ 面向对象的相关知识。看似简单的一道题,其实考查的点很多,题目还这么精炼有意思,好题!学海无涯,书山有路。每天一小步,总是在进步。耶!
最后,贴一下完整代码
class LazyMan {
constructor(name) {
// 虽然 lazyMan 很懒,但我们依然给他一个名字
this.name = name
// 我们把 lazyMan 要做的事情放在一个数组里
this.queue = []
// 第一个行为
const fn = (() => {
return () => {
console.log(`My name is ${name}`)
// 开始执行第二个行为
this.next()
}
})()
this.queue.push(fn)
// 等实例化完成开始执行队列任务
setTimeout(() => {
this.next()
}, 0)
}
/**
* next
* @memberof LazyMan
*/
next() {
// 把要执行的行为抽出来,并且执行一下
const fn = this.queue.shift()
fn && fn()
}
/**
* eat
* @param { String } what
* @return {*}
* @memberof LazyMan
*/
eat(what) {
// eat 是一个行为 我们用函数把它包裹起来
let fn = (() => {
// 用一个闭包把吃了什么记录下来
return () => {
console.log(`I ate ${what} !`)
// 行为完成,调用 next 方法,执行下一个行为
this.next()
}
})(what)
this.queue.push(fn)
// 返回 this 实现链式调用
return this
}
/**
* sleep
* @param { Number } hours
* @return {*}
* @memberof LazyMan
*/
sleep(hours) {
const _this = this
let fn = (function () {
return function () {
setTimeout(function () {
console.log(`I slept ${hours} hours ... ...`)
// 同样地,行为完成,调用 next 方法,执行下一个行为
_this.next()
}, hours * 1000)
}
})(hours)
// 同样地,把 sleep 行为放到队列里
this.queue.push(fn)
// 同样返回 this 实现链式调用
return this
}
}