javaScript 中防抖跟节流如何实现???

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
        <title>节流和防抖示例</title>
        <style type="text/css">
        body {
            height: 3000px;
        }

        .box {
			width:100px;
            height: 100px;
            overflow: scroll;
			font-size: 12px;
        }

        .box div {
            height: 3000px;
        }
        </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js"></script>
</head>

<body>
        <!-- <div class="box" id="box1" style="background: yellow;">
            <div>测试<span style="font-size:30px">节流</span>(首次不执行)</div>
        </div>
        <div class="box" id="box2" style="background: red;">
            <div>测试<span style="font-size:30px">节流</span>(首次执行)</div>
        </div> -->
        <input id="ipt" placeholder="测试防抖(首次不执行)">
        <button id="btn">111测试防抖首次执行(自己写的简化版)</button>
        <button id="btn2">2222测试防抖首次执行,到了一定的秒数继续执行(用lodash库)</button>
        <button id="btn3">333测试防抖首次执行,到了一定的秒数继续执行(用lodash库)</button>
        <script type="text/javascript">
		function throttle(fn, delay = 100) {
			//首先设定一个变量,在没有执行我们的定时器时为null
			let timer = null;
			return function () {
				//当我们发现这个定时器存在时,则表示定时器已经在运行中,需要返回
				if (timer) return;
				timer = setTimeout(() => {
					fn.apply(this, arguments);
					timer = null;
				}, delay);
			}
		}
		// document.getElementById('box1').onclick = throttle(function () {
		// 	console.log(1);
		// }, 5000);
        function throttle2(fn, delay = 100) {
            let last = 0;
            return function () {
                let curr = +new Date();
                if (curr - last > delay) {
                    fn.apply(this, arguments);
                    last = curr;
                }
            }
        }
        // document.getElementById('box2').onclick = throttle2(function () {
        //     console.log(2);
        // }, 3000);
	</script>
	<script type="text/javascript">
		function debounce(fn, delay = 200) {
			let timer = null;
			return function () {
				if (timer) clearTimeout(timer);
				timer = setTimeout(() => {
					fn.apply(this, arguments);
					timer = null;
				}, delay);
			}
		}
		/**
		 * @description: 防抖函数,当事件快速连续不断触发时,动作只会执行两次,首次执行一次,最后定时器执行一次
		 * @param {Function} fn 给函数设定防抖
		 * @param {Number} delay 间隔时间/秒
		 * @param {Blooean} firstExecutionFlag 是否立即执行
		 * @return {Function} 回调函数
		 */		
		function debounce2(fn, delay = 200, firstExecutionFlag = true) {
			let timer = null, last = 0, during;
			return function () {

				let self = this, args = arguments;

				var exec = function () {
					fn.apply(self, args);
				}
				console.log(firstExecutionFlag, !timer)
				if (firstExecutionFlag && !timer) {
					console.log(1)
					exec();
					firstExecutionFlag = false;
				} else {
					// console.log(2, 'Date.now()', Date.now())
					// console.log(2, 'last', last)
					// during = Date.now() - last;
					// console.log(2, 'during', during)
					// 注释掉这个代码就成每次执行一次了
					// if (during > delay && last > 0) {
					// 	console.log(Date.now(), last, during, delay);
					// 	exec();
					// } else {
						if (timer) clearTimeout(timer);

						timer = setTimeout(function () {
							exec();
						}, delay);
					// }
				}
				// last = Date.now();
			}
		}
		/**
		 * @description: 防抖函数,当事件快速连续不断触发时,动作只会执行两次,首次执行一次,最后定时器执行一次
		 * @param {Function} fn 给函数设定防抖
		 * @param {Number} delay 间隔时间/秒
		 * @param {Blooean} firstExecutionFlag 是否立即执行
		 * @return {Function} 回调函数
		 */	
		function debounce3(fn, delay = 500, firstExecutionFlag) {
			let timer;
			return function() {
				let that = this,
					args = arguments;
					
				if (timer) clearTimeout(timer); // 第二次进来如果有清空定时器,不会清空timer这个值
				if (firstExecutionFlag) { // 首次执行
					let flag = !timer; // 首次为空
					timer = setTimeout(() => { // 首次赋值
						timer = null;
					}, delay);
					if (flag) { // 首次会执行, --- 等第二次进来,发现 timer有值,不会执行
						fn.apply(that, args)
					}
				} else { // 首次不执行,靠时间执行的话,就判断是否有定时器,到指定的时间才会执行
					timer  = setTimeout(() => {
						fn.apply(that, args);
					}, delay)
				}
			}
		}
		
		document.getElementById('ipt').onkeydown = debounce(function () {
			console.log(3);
		}, 500);
		document.getElementById('btn').onclick = debounce(function () {
			console.log(4);
		}, 1000, 1);
		// document.getElementById('btn').onclick = debounce3(1000,1,function(){
		// 	console.log(4);
		// });
		document.getElementById('btn2').onclick = debounce2(function () {
			console.log(4, debounce2(function () {console.log('123')}));
		});
		document.getElementById('btn3').onclick = debounce3(function () {
			console.log(4);
		}, 1000, true);


	</script>
</body>

</html>