LazyMan题目讲解

来源:互联网 发布:java车辆管理系统源码 编辑:程序博客网 时间:2024/05/18 18:00

题目是从知乎上看到的: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实现

三、解题代码实现

1.ES5原生代码实现——个人手打调试

    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, ƒ]

2.ES6语法实现——ES6对this的控制简直完美,会ES5的实现ES6简直so easy

    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)    }

3.Promise语法实现——知乎网友南塔托给出的答案

对于这个答案我只能说如此精辟的解法要给一个大大的赞,使我对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方法会链式调用达到所需效果

原创粉丝点击