實現一個LazyMan,能夠按照如下方式調用:面試
LazyMan(「Hank」)輸出:bash
Hi! This is Hank!ui
LazyMan(「Hank」).sleep(10).eat(「dinner」)輸出this
Hi! This is Hank!spa
//等待10秒..prototype
Wake up after 10code
Eat dinner~cdn
LazyMan(「Hank」).eat(「dinner」).eat(「supper」)輸出blog
Hi This is Hank!string
Eat dinner~
Eat supper~
LazyMan(「Hank」).sleepFirst(5).eat(「supper」)輸出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper
以此類推。
嘗試着作了一下,發現沒有想象的簡單,雖然作出來了,可是若是是在面試的狀況下就壓力山大了,大廠就是不同!
如下是代碼,註釋省略
function LazyMan(obj) {
if (obj instanceof LazyMan) {
return obj
}
if (!(this instanceof LazyMan)) {
return new LazyMan(obj)
}
this.name = obj
this.cbManager = []
this.timer = null
this.say()
}
LazyMan.prototype.addCb = function (isAsync, cb) {
if (this.timer) {
this.cbManager.push({ isAsync, cb })
} else {
cb()
}
}
LazyMan.prototype.sleep = function (time) {
this.addCb(true, () => setTimeout(() => this.handleCb(), time * 1000))
return this
}
LazyMan.prototype.eat = function (food) {
this.addCb(false, () => console.log(food))
return this
}
LazyMan.prototype.sleepFirst = function (time) {
this.timer && clearTimeout(this.timer)
this.timer = setTimeout(() => this.say(), time * 1000)
return this
}
LazyMan.prototype.say = function () {
this.timer = setTimeout(() => {
console.log(this.name)
this.handleCb()
}, 0)
}
LazyMan.prototype.handleCb = function () {
const next = this.cbManager.shift()
if (next) {
next.cb()
!next.isAsync && this.handleCb()
}
}
// LazyMan('Hank')
// LazyMan('Hank').eat('dinner').eat('supper')
// LazyMan('hank').sleep(5).eat('dinner')
// LazyMan('hank').sleep(5).eat('dinner').sleep(5).eat('supper')
LazyMan('Hank').sleepFirst(5).eat('supper').sleep(5).eat('dinner')
複製代碼
三個月後再看這道題,總以爲上面這個實現方式不太優雅,所以換個思路實現,如下是代碼:
function LazyMan(name) {
if (!(this instanceof LazyMan)) {
return new LazyMan(name)
}
const cb = next => {
console.log(`hi, this is ${name}`)
next()
}
this.cbs = [cb]
setTimeout(() => this.next(), 0)
}
LazyMan.prototype.sleep = function (time) {
const cb = next => setTimeout(() => next(), time * 1000)
this.cbs.push(cb)
return this
}
LazyMan.prototype.sleepFirst = function (time) {
const cb = next => setTimeout(() => next(), time * 1000)
this.cbs.unshift(cb)
return this
}
LazyMan.prototype.eat = function (food) {
const cb = next => {
console.log(`eat ${food}`)
next()
}
this.cbs.push(cb)
return this
}
LazyMan.prototype.next = function () {
if (this.cbs.length <= 0) return
const first = this.cbs.shift()
first(this.next.bind(this))
}
複製代碼
不知道有沒有更優雅的方法