题目是从知乎上看到的:https://zhuanlan.zhihu.com/p/28892523?utm_medium=social&utm_source=qq
实现一个LazyMan,可以按照以下方式调用:
LazyMan(“Hank”)输出:
Hi! This is Hank!
LazyMan(“Hank”).sleep(10).eat(“dinner”)输出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~
LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出
Hi This is Hank!
Eat dinner~
Eat supper~
LazyMan(“Hank”).sleepFirst(5).eat(“supper”)输出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper
以此类推。
1.整体是一个js的面向对象编程的题目
2.涉及到异步控制的思想
3.执行顺序不同于调用顺序
4.可以考虑内部维护一个数组控制调用顺序
5.可以考虑使用Promise实现
6.可以考虑使用async实现
function Man(name) {
this.actions = [];
this.current = 0;
var helloFunc = function () {
console.log("Hi This is " + name + "!");
this.act();
}.bind(this)
this.addAction(helloFunc);
setTimeout(function () {
this.act();
}.bind(this), 0);
}
// 调用下一个动作
Man.prototype.act = function () {
var actions = this.actions;
return actions[this.current] && actions[this.current++]();
}
// 向动作队列添加动作
Man.prototype.addAction = function (func, isFirst) {
if (!isFirst) {
this.actions.push(func);
} else {
this.actions.unshift(func);
}
}
// 休眠
Man.prototype.sleep = function (time) {
var sleepFunc = function () {
setTimeout(function () {
console.log("Wake up after " + time + "ms");
this.act();
}.bind(this), time)
}.bind(this);
this.addAction(sleepFunc);
return this;
}
// 吃饭
Man.prototype.eat = function (food) {
var eatFunc = function () {
console.log("Eat " + food + "~");
this.act();
}.bind(this);
this.addAction(eatFunc);
return this;
}
// 睡觉优先
Man.prototype.sleepFirst = function (time) {
var sleepFirstFunc = function () {
setTimeout(function () {
console.log("Wake up after " + time + "ms");
this.act();
}.bind(this), time)
}.bind(this);
this.addAction(sleepFirstFunc, true);
return this;
}
function LazyMan(name) {
return new Man(name);
}
var helloFunc = function () {
console.log("Hi This is " + name + "!");
this.act();
}.bind(this)
.bind(this)
那么this
指向哪里?答案是 this.actions为什么会出现这种情况呢?
javascript的this
指向执行时的上下文对象
那么this.act()何时执行呢?答案是
return actions[this.current] && actions[this.current++]();
所以必须使用.bind(this)
改变this的指向
简化版可以参考这个代码:
var a = [0,1,2,function(){console.log(this)}];
a[3]();
输出结果为:[0, 1, 2, ƒ]
class Man{
constructor(name){
this.actions = [];
this.current = 0;
var helloFunc = () =>{
console.log("Hi This is " + name + "!");
this.act();
}
this.addAction(helloFunc);
setTimeout(() =>{
this.act();
}, 0)
}
act(){
var actions = this.actions;
return actions[this.current] && actions[this.current++]();
}
addAction(func, isFirst){
if(!isFirst){
this.actions.push(func)
}else{
this.actions.unshift(func)
}
}
eat(food){
var eatFunc = () =>{
console.log("Eat " + food + "~");
this.act();
}
this.addAction(eatFunc)
return this;
}
sleep(time){
var sleep = () =>{
setTimeout(() => {
console.log("Wake up after " + time + "ms");
this.act();
}, time)
}
this.addAction(sleep);
return this;
}
sleepFirst(time){
var sleepFirst = () =>{
setTimeout(() =>{
console.log("Wake up after " + time + "ms");
this.act();
}, time)
}
this.addAction(sleepFirst, true)
return this;
}
}
function LazyMan(name) {
return new Man(name)
}
对于这个答案我只能说如此精辟的解法要给一个大大的赞,使我对Promise
的认识更深了一层。
class Lazy {
constructor(name) {
this.sleepFirstTime = 0;
this.promise = Promise.resolve().then(
() => this.sleepFirstTime && this._sleep(this.sleepFirstTime)
).then(() => {
console.log(`Hi! This is ${name}!`);
});
}
sleepFirst(time) {
this.sleepFirstTime = time;
return this;
}
eat(food) {
this.promise = this.promise.then(() => {
console.log(`Eat ${food}~`);
});
return this;
}
sleep(time) {
this.promise = this.promise.then(() => this._sleep(time));
return this;
}
_sleep(time) {
return new Promise((next) => {
setTimeout(() => {
console.log(`Wake up after ${time}`);
next();
}, time);
});
}
}
function LazyMan(name) {
return new Lazy(name);
}
constructor(name) {
this.sleepFirstTime = 0;
// Promise.resolve()创建一个Promise对象执行后面的函数
this.promise = Promise.resolve().then(
// this.sleepFirstTime为0时后面的函数不会执行
() => this.sleepFirstTime && this._sleep(this.sleepFirstTime)
).then(() => {
console.log(`Hi! This is ${name}!`);
});
}
假设执行该函数
LazyMan(“Hank”).sleepFirst(2000).sleep(2000).eat(“supper”)
【注意】构造函数初始化时仅执行了this.promise = Promise.resolve()
此时的this.promise仅仅是一个Promise对象
.then
会在.eat("super")
结束后才调用
然后.sleepFirst
等函数对this.promise
进行了改造
最后各种.then
方法会链式调用达到所需效果