前端面试练习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 }
相关推荐
小肝一下1 小时前
每日两道力扣,day2
c++·算法·leetcode·职场和发展
程序员小寒1 小时前
JavaScript设计模式(八):命令模式实现与应用
前端·javascript·设计模式·ecmascript·命令模式
wgod2 小时前
new AbortController()
前端
UXbot2 小时前
UXbot 是什么?一句指令生成完整应用的 AI 工具
前端·ai·交互·个人开发·ai编程·原型模式·ux
棒棒的唐2 小时前
WSL2用npm安装的openclaw,无法正常使用openclaw gateway start启动服务的问题
前端·npm·gateway
米粒12 小时前
力扣算法刷题 Day 31 (贪心总结)
算法·leetcode·职场和发展
哔哩哔哩技术2 小时前
使用Compose Navigation3进行屏幕适配
前端
AlenTech2 小时前
647. 回文子串 - 力扣(LeetCode)
算法·leetcode·职场和发展
咬人喵喵3 小时前
E2.COOL 平台深度解析:从特效分类到实战操作指南
前端·编辑器·svg
RisunJan4 小时前
Linux命令-named-checkzone
linux·前端