前端面试宝典

该题考察的是性能,体验优化方案,闭包。

防抖:时间被连续触发的情况下,只执行最后一次的事件

节流:时间间隔相等的(频率不变)的执行被频繁触发的事件。

防抖

核心思想:触发事件后,函数不会立即执行,而是等待一段时间(比如 n 秒)。

如果在这段时间内再次触发事件,则重新计时。只有当事件触发后,在 n 秒内没有再次触发,函数才会执行。

应用场景:搜索框输入联想(等待用户停止输入后再发送请求)、窗口 resize 后调整布局等。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
	  // 防抖:防止抖动,多次触发只执行一次
	  // 用户输入完成后在进行关键词推荐,监听窗口(resize)变化
      function debounce(fn, delay) {
        let timer = null;
        return (...args) => {
          if (timer) {
            clearTimeout(timer);
          }
          timer = setTimeout(() => {
            fn.apply(this, args);
			timer = null;// 清除定时器,防止内存泄露
          }, delay);
        };
      }

      // 测试
      window.addEventListener("resize",debounce(() => {
          console.log("防抖");
        }, 1000)
      );
    </script>
  </body>
</html>

节流

节流原理
规定一个时间间隔(比如 n 秒),在这个时间间隔内,函数只会执行一次。
如果在这段时间内多次触发事件,只有第一次(或最后一次)会生效。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
	  // 节流:节省流量,控制执行频率,规定时间内只执行一次
      function throttle(fn, interval) {
        let lastTime = 0;
        return function (...args) {
          const now = Date.now();
          // 如果当前时间与上次执行时间的差大于间隔,则执行
          if (now - lastTime >= interval) {
            fn.apply(this, args);
            lastTime = now;// 更新上次执行时间
          }
        };
      }

      // 测试
      window.addEventListener(
        "scroll",
        throttle(() => {
          console.log("节流");
        }, 1000)
      );
    </script>
  </body>
</html>

深拷贝

function deepCopy(obj) {
	// 处理null 和 undefined
	if (obj === null || typeof obj !== 'object') {
		return obj;
	}

	// 处理日期
	if (obj instanceof Date) {
		return new Date(obj);
	}

	// 处理正则
	if (obj instanceof RegExp) {
		return new RegExp(obj.source, obj.flags);
	}

	// 处理数组和对象
	let copy = Arry.isArray(obj) ? [] : {};

	// 递归拷贝属性
	Object.keys(obj).forEach(key => {
		copy[key] = deepCopy(obj[key]);
	})

	return copy;
}