前端简单的红绿灯实现 JS

const serial = ['Red', 'Yellow', 'Green']

/**
 * 延迟指定时间后返回一个Promise对象
 * 
 * @param {number} time - 延迟的时间,以毫秒为单位,默认为1000ms
 * @returns {Promise} 返回一个Promise对象
 */
function delay(time = 1000) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve()
        }, time)
    })
}
class Singal {
    //获取下一个信号灯颜色
    get next() {
        return serial[(serial.indexOf(this.sig) + 1) % serial.length];
    }
    //剩余时间
    get remain() {
        let diff = this.end - Date.now();
        if (diff < 0) {
            diff = 0;
        }
        return diff / 1000;
    }
    //构造函数
    constructor(options) {
        this.sig = options.init;
        this.times = options.times;
        this.eventMap = new Map();
        this.eventMap.set('change', new Set())
        this.eventMap.set('tick', new Set())
        this.setTime()
        this.exchange()
    }
    // 注册事件
    on(event, handler) {
        this.eventMap.get(event).add(handler);
    }
    // 取消注册事件
    off(event, handler) {
        this.eventMap.get(event).delete(handler);
    }
    // 触发事件
    emit(event) {
        this.eventMap.get(event).forEach(h => h.call(this, this));
    }
    //交换信号灯颜色
    async exchange() {
        await 1;
        if (this.remain > 0) {
            //不需要切换
            this.emit('tick');
            await delay(1000)
        } else {
            this.sig = this.next;
            this.setTime();
            this.emit('change');
        }
        //递归调用
        this.exchange();
    }
    //设置时间
    setTime() {
        //获取开始时间
        this.start = Date.now();
        //获取等待时间
        const time = this.times[serial.indexOf(this.sig)]
        //设置结束时间
        this.end = this.start + time * 1000;
    }
}
const s = new Singal({
    init: 'Red',
    times: [10, 3, 5]
});
s.on('tick', (e) => {
    console.log(e.sig, Math.round(e.remain));
})
/***
 * new Map()
 * Map是ES6中的一种数据结构,它允许您将键值对存储在一个可迭代的集合中。与JavaScript中的其他对
象(例如对象字面量)相比,Map提供了更灵活的键和更容易使用的API。

以下是创建和使用Map对象的示例:
// 创建一个空的Map对象
var myMap = new Map();

// 添加键值对到Map中
myMap.set('key1', 'value1');
myMap.set('key2', 'value2');
myMap.set('key3', 'value3');

// 从Map中获取值
console.log(myMap.get('key1')); // 输出 "value1"

// 检查Map中是否包含指定的键
console.log(myMap.has('key2')); // 输出 true

// 删除指定的键值对
myMap.delete('key3');

// 遍历Map中的所有键值对
for (var [key, value] of myMap) {
    console.log(key + ' = ' + value);
}

在上述代码中,我们首先创建一个空的Map对象,然后使用set()方法向其中添加三个键值对。接着,我们使
用get()方法获取一个指定键对应的值,并使用has()方法检查指定键是否存在于Map中。然后,我们使用
delete()方法删除一个键值对,并使用for...of循环遍历Map中的所有键值对。

需要注意的是,在使用Map时,键可以是任何类型的值,包括字符串、数字、对象等。此外,Map对象是有序
的,即键值对的顺序与它们添加到Map中的顺序相同。
 */

/***
 *  new Set()
 * Set是ES6中的一种数据结构,它允许您存储唯一的值(无重复)。Set类似于数组,但是它们的主要区别
在于Set中的值不能重复,而数组可以包含重复的元素。
 * 以下是创建和使用Set对象的示例:
 // 创建一个空的Set对象
var mySet = new Set();

// 添加元素到Set中
mySet.add('value1');
mySet.add('value2');
mySet.add('value3');

// 检查Set中是否包含指定的值
console.log(mySet.has('value2')); // 输出 true

// 从Set中删除指定的值
mySet.delete('value3');

// 获取Set中的元素数量
console.log(mySet.size); // 输出 2

// 遍历Set中的所有元素
mySet.forEach(function(value) {
  console.log(value);
});
在上述代码中,我们首先创建一个空的Set对象,然后使用add()方法将三个值添加到Set中。接着,我们使
用has()方法检查指定的值是否存在于Set中,并使用delete()方法删除一个值。还可以使用size属性获取
Set中的元素数量。最后,我们使用forEach()方法遍历Set中的所有元素。

需要注意的是,Set中的值可以是任何类型的值,包括基本类型和对象。Set对象中的元素是按照它们被添加
到Set中的顺序进行迭代。另外,Set自动处理值的唯一性,即不会添加重复的值。
 */
/***
 在上述代码中,this.exchange()函数被设置为每隔1秒调用一次。在每次调用this.exchange()函数时,
会通过this.emit('tick')触发tick事件。因此,如果要在接收到tick事件时执行相应的回调函数,必须在
代码中调用on('tick', callback)来注册tick事件的回调函数。这样,当tick事件被触发时,就会执行注
册的回调函数。如果没有调用on('tick', callback)来注册tick事件的回调函数,那么就无法在接收到
tick事件时执行相应的操作。 
 * */

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
百度外包前端面试题红绿灯是一个经典的异步编程问题。题目要求红灯每隔3秒亮一次,绿灯每隔1秒亮一次,黄灯每隔2秒亮一次,并且三个灯需要交替重复亮灯。 题目给出的代码只完成了一次流程,即红灯亮一次,黄灯亮一次,绿灯亮一次。但题目要求的是交替重复亮灯,所以需要对代码进行修改。 可以使用回调函数的方式来实现交替重复亮灯。首先定义一个任务函数`task`,该函数接收三个参数:计时器时间、灯的颜色和回调函数。在`task`函数内部使用`setTimeout`函数来设置定时器,在定时器的回调函数中判断当前灯的颜色并执行相应的操作,然后调用回调函数。在回调函数中再次调用`task`函数来实现循环调用。 具体实现如下: ```javascript const task = (timer, light, callback) => { setTimeout(() => { if (light === 'red') { red() } else if (light === 'green') { green() } else if (light === 'yellow') { yellow() } callback() }, timer) } task(3000, 'red', () => { task(1000, 'green', () => { task(2000, 'yellow', () => { task(3000, 'red', Function.prototype) }) }) }) ``` 上述代码实现红绿灯的交替重复亮灯,首先通过调用`task`函数来启动红灯,然后在红灯的回调函数中调用`task`函数启动绿灯,再在绿灯的回调函数中调用`task`函数启动黄灯,最后在黄灯的回调函数中再次调用`task`函数启动红灯,从而实现红绿灯的交替重复亮灯。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [美团前端一面必会手写面试题汇总](https://blog.csdn.net/helloworld1024fd/article/details/127582853)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值