實現一個LazyMan,能夠按照如下方式調用:面試
LazyMan(「Hank」)輸出:bash
Hi! This is Hank!markdown
LazyMan(「Hank」).sleep(10).eat(「dinner」)輸出this
Hi! This is Hank!spa
//等待10秒..prototype
Wake up after 10code
Eat dinner~orm
LazyMan(「Hank」).eat(「dinner」).eat(「supper」)輸出it
Hi This is Hank!io
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)) } 複製代碼
不知道有沒有更優雅的方法