经典面试题 LazyMan

267 阅读2分钟

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

导言

刷视频时发现的一道题,发现听有意思的,主要是考对数据结构中队列的了解。

LazyMan

1. 要求效果:

  1. 当输入:

LazyMan('张三').eat('lunch')

  • 需要输出:

你好,我叫张三

吃午餐

  1. 当输入

LazyMan('张三').sleep('5').eat('dinner')

  • 需要输出:

你好,我叫张三

(等待5秒)

我醒了,我刚睡了5秒

吃晚餐

  1. 当输入

LazyMan('张三').sleepFirst('5').eat('lunch').sleep('5').eat('dinner')

  • 需要输出:

(等待5秒)

我醒了,我刚睡了5秒

你好,我叫张三

吃午餐

(等待5秒)

我醒了,我刚睡了5秒

吃晚餐

2. 解题思路

咋的一看,第一二效果感觉挺容易,但主要是第三个,就很难了,需要将 sleepFirst() 这个方法提前执行。看到这里其实就很容易想到 js 中的异步队列是不是,原理上其实都一样,利用数据结构中的队列实现。

那么解题思路就很清晰了:在函数体内维护一个队列,将所有方法通过 unshift 和 push 将插入到队列中, 随后使用一个 next() 方法, 不断将队列中的第一个方法取出调用。同时在每个方法的最后都返回一个 api 对象,来实现连式编程。总而言之就是在遇见方法时就将其插入到队列的最后,遇见需要先执行的方法,就将其插入到队列的最前方。

3. 具体代码

const LazyMan = name => {
    // 维护一个队列
    var queue = []
    // 输出名字方法
    const names = () => {
        console.log(`你好,我叫${name}`)
        next()
    }
    // 将输出名字方法插入这个队列
    queue.push(names)
    // 添加 next() 方法,负责将队列中第一个方法取出并执行
    const next = () => {
        // 如果队列中没有方法了就停止执行
        if(queue.length <= 0) return false
        // 使用数组中的 shift 方法将队列中的第一位取出
        const first = queue.shift()
        // 执行第一个方法
        first()
    }
    // 声明一个 api 对象,当做自身方法扩展,实现链式编程
    var api = {
        // 程序运行到这里需要暂停指定时间
        sleep(delay){
            // 将这个方法 push 进队列
            const sleeps = () => {
                setTimeout(() => {
                    console.log(`我醒了,我刚睡了${delay}秒`)
                    next()
                }, delay * 1000)
            }
            queue.push(sleeps)
            // 返回对象
            return api
        },
        // 表示代码在执行前需要暂停多久
        sleepFirst(delay){
            // 使用 unshift 将这个定时器插入队列的首位
            const sleepFirsts = () => {
                setTimeout(() => {
                    console.log(`我醒了,我刚睡了${delay}秒`)
                    next()
                }, delay * 1000)
            }
            queue.unshift(sleepFirsts)
            return api
        },
        // 吃晚餐还是吃午餐
        eat(lunch){
            const eats = () => {
                // 使用三元表达式完成
                console.log(lunch == 'lunch' ? '吃午餐' : '吃晚餐')
                next()
            }
            queue.push(eats)
            // 每个方法最后都得返回这个 api 对象,
            return api
        }
    }
    // 调用 next() 开始执行方法
    setTimeout(() => {
        next()
    }, 100)
    // 将这个 api 对象返回出去形成链式编程
    return api
}