Skip to content

题目描述

请实现一个 HardMan(name) 函数,支持链式调用以下方法:

  1. study():表示开始学习,输出 "I am studying"
  2. rest(sec):表示休息,等待 sec 秒后输出 "I have rested for ${sec} seconds",然后继续执行后续链式调用。
  3. restFirst(sec):在做所有事情之前先休息 sec 秒钟

示例:

HardMan(jiaqi).study().rest(5).study().restFirst(10)

说明:

  • 输出应依次为:
    • `My name is jiaqi
    • (等待10秒)
    • "Yeah, I have rested for 10 seconds"
    • "I am studying"
    • (等待5秒)
    • "I have rested for 5 seconds"
    • "I am studying"

用类实现

javascript
class HardMan {
    constructor(name) {
        this.queue = []; // 初始化一个队列
        console.log(`My name is ${name}`);
        Promise.resolve().then(() => {
            let sequence = Promise.resolve();
            this.queue.forEach((item) => {
                sequence = sequence.then(item);
            });
        })
    }

    study() {
        this.queue.push(() => {
            console.log("I am studying");
        });
        return this; // 返回实例以支持链式调用
    }

    holdOn(sec) {
        return () => {
            return new Promise((resolve) => { 
            // 注意箭头函数中的 return
                setTimeout(() => {
                    console.log(`rest for ${sec} seconds`);
                    resolve(); // 
                }, sec * 1000);
            });
        }
    }

    rest(sec) {
        this.queue.push(this.holdOn(sec));
        return this; // 返回实例以支持链式调用
    }

    restFirst(sec) {
        this.queue.unshift(this.holdOn(sec));
        return this; // 返回实例以支持链式调用
    }
}

// 测试代码
let jiaqi = new HardMan("jiaqi");
jiaqi
    .study()
    .rest(5)
    .study()
    .restFirst(2);

在这里最需要注意的是 holdOn 函数的返回值,要与[[202407012319-LazyMan]] 中相应的返回值一起理解,理解箭头函数的返回值。

[!PDF|yellow] [[JavaScript权威指南(原书第7版)(经典的JavaScript犀牛书全新升级) (O''''Reilly精品图书系列)_LT.pdf#page=475&selection=15,0,18,30&color=yellow|📖]]

在期约链中,一个环节返回(或抛出)的值会成为下一个环节的输入。因此每个环节返回什么至关重要。实际开发中,忘记从回调函数中返回值是导致期约相关问题的常见原因。而使用 JavaScript的箭头函数快捷语法又让这个问题雪上加霜。

当箭头函数没有大括号包裹时,箭头函数会隐式地返回单个表达式的值。

当箭头函数有大括号包裹时,需要用 return 显式地返回值。

用函数实现

javascript
function HardMan(name) {
    let queue = [];
    Promise.resolve().then(()=>{
        let sequence = Promise.resolve();
        queue.forEach((item)=>{
            sequence = sequence.then(item);
        });
    })

    console.log(`My name is ${name}`);

    // 立即返回三个方法,以便支持链式调用
    return {
        study() {
            queue.push(() => {
                console.log("I am studying");
            });
            return this; // 返回当前对象以支持链式调用
        },

        holdOn(sec){
            return ()=>{
                return new Promise((resolve)=>{
                    setTimeout(()=>{
                        console.log(`rest for ${sec} seconds`);
                        resolve();
                    }, sec * 1000);
                });
            }
        },

        rest(sec) {
            queue.push(this.holdOn(sec));
            return this; // 返回当前对象以支持链式调用
        },

        restFirst(sec) {
            queue.unshift(this.holdOn(sec));
            return this; // 返回当前对象以支持链式调用
        }
    };
}

// 测试代码
HardMan("jiaqi")
    .study()
    .rest(5)
    .study()
    .restFirst(2);