实现一个LazyMan

这个算是网上流传较广的经典的腾讯面试题目了,重新遇到的机会应该不大,但是感觉挺有意义的,比起那些问api的面试题有趣得多。

题目

实现一个LazyMan,可以按照以下方式调用:
LazyMan(“Hank”)输出:

1
Hi! This is Hank!


LazyMan(“Hank”).sleep(10).eat(“dinner”)输出

1
2
3
4
Hi! This is Hank!
//等待10秒…
Wake up after 10
Eat dinner~


LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出

1
2
3
Hi This is Hank!
Eat dinner~
Eat supper~


LazyMan(“Hank”).sleepFirst(5).eat(“supper”)输出

1
2
3
4
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper

分析

  1. 首先全部操作都会形成链式操作,就是说每个函数执行完毕都应该返回自身以方便形成链式调用。
  2. sleepFirst()函数有点需求不明确,First是指它只能用在第一个调用函数,还是说只要执行了这个函数不管位置都会先执行这个函数呢。因此,这里就把这个函数当做优先级最高处理,就是说会先执行这个函数。
  3. 后一个函数需要在上一个函数执行完成后才能执行。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
function LazyMan(name) {
return new LazyManObj(name)
}

function LazyManObj(name) {
this.name = name
this.queue = []
this.sayHi()
// 先执行完主线程的task
setTimeout(() => {
this.next()
}, 0)
}

LazyManObj.prototype.next = function () {
let task = this.queue.shift()
task && task()
}

LazyManObj.prototype.sayHi = function () {
this.queue.push(() => {
console.log(`This is ${this.name}!`)
this.next()
})
return this
}

LazyManObj.prototype.sleep = function (time) {
this.queue.push(() => {
setTimeout(() => {
console.log(`Wake up after ${time}`)
this.next()
}, time * 1000)
})
return this
}

LazyManObj.prototype.eat = function (something) {
this.queue.push(() => {
console.log(`Eat ${something}`)
this.next()
})
return this
}

LazyManObj.prototype.sleepFirst = function(time) {
this.queue.unshift(() => {
setTimeout(() => {
console.log(`Wake up after ${time}`)
this.next()
}, time * 1000)
})
return this
}

LazyMan("Hank").eat("dinner").sleepFirst(3).eat("supper")

主要有几点要注意:

初始化中的setTimeout有什么用

1
2
3
setTimeout(() => {
this.next()
}, 0)

主线程使用setTimeout来控制开始函数,目的是把this.next()加入到macrotask中,那么等链式的函数全部加入到queue以后再执行,这是event loop的基础部分,不详细展开。

为什么要返回this

1
return this

可以看到,每个函数执行后都会返回一个this,这个this就是相当于LazyManObj本身,通过返回的这个Obj就可以继续调用其他的方法,以形成链式调用。

总结

总的来说其实不难,主要考察的点是Event Loop的知识。