前端面试练习24.3.8

防抖和节流

防抖(Debouncing):

防抖是指在短时间内连续触发同一事件时,只执行最后一次触发的事件处理函数。

在实际应用中,常常用于处理用户输入的搜索框或者滚动事件。例如,当用户连续输入搜索关键词时,如果没有防抖处理,每次输入都会触发搜索请求,造成不必要的请求发送和资源浪费。而通过防抖技术,可以等待一定的时间间隔,只有在用户停止输入后才触发搜索请求,从而减少请求次数,提高性能。

节流(Throttling):

节流是指在一定时间间隔内只执行一次事件处理函数。

与防抖不同的是,节流不会等待最后一次触发事件,而是在规定的时间间隔内执行事件处理函数,然后忽略剩余的触发事件。

节流常用于处理滚动事件、窗口调整大小事件等频繁触发的事件。例如,在网页中,当用户快速滚动页面时,如果没有节流处理,滚动事件会频繁触发,影响页面性能和流畅度。而通过节流技术,可以限制滚动事件的触发频率,使页面能够更加平滑地滚动。

代码实现:

javascript 复制代码
/**
 * 防抖函数,在一定时间内只执行一次函数,避免函数因频繁触发而过度消耗性能
 *
 * @param func 要防抖的函数
 * @param wait 等待时间,单位为毫秒
 * @returns 返回防抖后的函数
 */
function debounce(func, wait) {
  // 定义一个变量timeoutId,用于存储setTimeout的返回值
  let timeoutId;

  // 返回一个函数
  return function () {
    // 获取当前函数的上下文和参数
    const context = this;
    const args = [...arguments];

    // 如果timeoutId存在,则清除之前的setTimeout定时器
    if (timeoutId) clearTimeout(timeoutId);

    // 设置一个新的setTimeout定时器,等待wait毫秒后执行func函数,并将上下文和参数传递给func函数
    timeoutId = setTimeout(() => {
      func.apply(context, args);
    }, wait);
  };
}


// 节流函数
/**
 * 节流函数,限制函数的执行频率
 *
 * @param func 要进行节流的函数
 * @param wait 两次执行之间的时间间隔,单位毫秒
 * @returns 返回一个新的函数,该函数在wait毫秒内只执行一次func函数
 */
function throttle(func, wait) {
  // 定义一个变量lastTime,用于存储上一次触发的时间
  let lastTime = 0;
  // 返回一个函数
  return function () {
    // 获取当前函数的上下文和参数
    const context = this;
    const args = [...arguments];
    // 获取当前时间戳
    const now = Date.now();
    // 如果距离上次触发的时间间隔大于wait毫秒,则执行func函数,并更新lastTime为当前时间戳
    if (now - lastTime >= wait) {
      func.apply(context, args);
      lastTime = now;
    }
  };
}

/**
 * 节流函数,限制函数的执行频率
 *
 * @param func 要进行节流的函数
 * @param interval 两次执行之间的时间间隔,单位毫秒
 * @returns 返回一个新的函数,该函数在 interval 毫秒内只执行一次 func 函数
 */
function throttle(func, interval) {
  // 定义一个定时器ID
  let timeoutId;

  // 返回一个新的函数
  return function (...args) {
    // 获取当前上下文
    const context = this;

    // 如果定时器ID不存在
    if (!timeoutId) {
      // 设置定时器
      timeoutId = setTimeout(() => {
        // 在定时器回调函数中执行原始函数,并传入参数
        func.apply(context, args);
        // 将定时器ID置为null
        timeoutId = null;
      }, interval);
    }
  };
}

原生JS实现懒加载

方案一

使用getBoundingClientRect()方法用于获取元素的大小及其相对于视口的位置信息

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Lazy Loading Example</title>
  <style>
    .lazy-img {
      width: 100%;
      height: 200px;
      background: #ccc;
      margin: 10px 0;
    }
  </style>
</head>
<body>
  <div class="lazy-img-container">
    <img class="lazy-img" data-src="image1.jpg" alt="Image 1">
    <img class="lazy-img" data-src="image2.jpg" alt="Image 2">
    <img class="lazy-img" data-src="image3.jpg" alt="Image 3">
    <!-- 更多图片 -->
  </div>

  <script>
    document.addEventListener("DOMContentLoaded", function() {
      var lazyImages = document.querySelectorAll('.lazy-img');

      var lazyLoad = function() {
        lazyImages.forEach(function(img) {
          if (img.getBoundingClientRect().top < window.innerHeight && !img.src) {
            img.src = img.dataset.src;
          }
        });
      };

      // 第一次加载页面时执行一次懒加载
      lazyLoad();

      // 滚动事件触发时检查是否需要加载图片
      window.addEventListener('scroll', lazyLoad);
    });
  </script>
</body>
</html>

方案二

通过计算得到一些数据

(1) window.innerHeight 是浏览器可视区的高度

(2) document.body.scrollTop || document.documentElement.scrollTop 是浏览器滚动的过的距离

(3) imgs.offsetTop 是元素顶部距离文档顶(3)部的高度(包括滚动条的距离)

(4) 图片加载条件:img.offsetTop - document.body.scrollTop< window.innerHeight ;

图示:

判断打印结果(参数传递修改,创建实例)

解释:

在这段代码中,首先创建了一个名为 p1 的对象,该对象包含了 nameage 属性。然后定义了一个名为 test 的函数,该函数接受一个参数 person。在函数内部,首先修改了传入的 person 对象的 age 属性为 26,然后又重新赋值了 person 对象为一个新的对象 { name: 'hzj', age: 18 }。最后返回了这个新对象。

在函数外部,调用 test 函数时将 p1 对象传入,并将返回值赋给了变量 p2。因为 JavaScript 中的对象是按引用传递的,所以当在函数内部修改 person 对象时,实际上是在修改传入的对象的引用,因此 p1 对象的 age 属性也会被修改为 26。但是在重新赋值 person 对象后,p1 对象不会受到影响,因为此时 person 变量指向了一个新的对象。因此最终输出 p1 对象时,其 age 属性为 26;而输出 p2 对象时,其 age 属性为 18

javascript 复制代码
const p1 = {
  name: 'fyg',
  age: 19
};

function test(person) {
  person.age = 26;
  person = {
    name: 'hzj',
    age: 18
  };
  return person;
}

const p2 = test(p1);
console.log(p1); // { name: 'fyg', age: 26 }
console.log(p2); // { name: 'hzj', age: 18 }
相关推荐
大怪v6 小时前
AI抢饭?前端佬:我要验牌!
前端·人工智能·程序员
新酱爱学习6 小时前
字节外包一年,我的技术成长之路
前端·程序员·年终总结
小兵张健6 小时前
开源 playwright-pool 会话池来了
前端·javascript·github
IT_陈寒9 小时前
Python开发者必知的5大性能陷阱:90%的人都踩过的坑!
前端·人工智能·后端
codingWhat9 小时前
介绍一个手势识别库——AlloyFinger
前端·javascript·vue.js
代码老中医9 小时前
2026年CSS彻底疯了:这6个新特性让我删掉了三分之一JS代码
前端
不会敲代码19 小时前
Zustand:轻量级状态管理,从入门到实践
前端·typescript
踩着两条虫9 小时前
VTJ.PRO 双向代码转换原理揭秘
前端·vue.js·人工智能
扉川川9 小时前
OpenClaw 架构解析:一个生产级 AI Agent 是如何设计的
前端·人工智能
远山枫谷9 小时前
一文理清页面/组件通信与 Store 全局状态管理
前端·微信小程序