面试典籍(整理于6.24-6.30)

防抖(debounce)函数的作用是什么?有哪些应用场景,请实现一个防抖函数

  • 防抖函数的作用

防抖函数的作用就是控制函数在一定时间内的执行次数。防抖意味着N秒内函数只会被执行一次,如果N秒内再次被触发,则重新计算延迟时间。

举例说明:小思最近在减肥,但是她非常贪吃。为此,与其男朋友约定好,如果10天不吃零食,就可以购买一个包(不要问为什么是包,因为包治百病)。但是如果中间吃了一次零食,那么就要重新计算时间,直到小思坚持10天没有吃零食,才能购买一个包。所以,管不住嘴的小思,没有机会买包(悲伤的故事)...这就是防抖

不管吃没吃零食,每10天买一个包,中间想买包,忍着,等到第十天的时候再买,这种情况是节流。如何控制女朋友的消费,各位攻城狮们,get到了吗?防抖可比节流有效多了!

  • 防抖应用场景
  1. 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
  2. 表单验证
  3. 按钮提交事件。
  4. 浏览器窗口缩放,resize事件等。
  • 防抖函数实现
  1. 事件第一次触发时,timernull,调用 later(),若 immediatetrue,那么立即调用 func.apply(this, params);如果 immediatefalse,那么过 wait 之后,调用 func.apply(this, params)
  2. 事件第二次触发时,如果 timer 已经重置为 null(即 setTimeout 的倒计时结束),那么流程与第一次触发时一样,若 timer 不为 null(即 setTimeout 的倒计时未结束),那么清空定时器,重新开始计时。
function debounce(func, wait, immediate = true) {
    let timer;
    // 延迟执行函数
    const later = (context, args) => setTimeout(() => {
        timer = null;// 倒计时结束
        if (!immediate) {
            func.apply(context, args);
            //执行回调
            context = args = null;
        }
    }, wait);
    let debounced = function (...params) {
        let context = this;
        let args = params;
        if (!timer) {
            timer = later(context, args);
            if (immediate) {
                //立即执行
                func.apply(context, args);
            }
        } else {
            clearTimeout(timer);
            //函数在每个等待时延的结束被调用
            timer = later(context, args);
        }
    }
    debounced.cancel = function () {
        clearTimeout(timer);
        timer = null;
    };
    return debounced;
};

immediate 为 true 时,表示函数在每个等待时延的开始被调用。

immediate 为 false 时,表示函数在每个等待时延的结束被调用。

原创链接地址 :防抖(debounce)函数

节流(throttle)函数的作用是什么?有哪些应用场景,请实现一个节流函数

  • 节流函数的作用

节流函数的作用是规定一个单位时间,在这个单位时间内最多只能触发一次函数执行,如果这个单位时间内多次触发函数,只能有一次生效。

举例说明:小明的妈妈和小明约定好,如果小明在周考中取得满分,那么当月可以带他去游乐场玩,但是一个月最多只能去一次。

这其实就是一个节流的例子,在一个月的时间内,去游乐场最多只能触发一次。即使这个时间周期内,小明取得多次满分。

  • 节流应用场景
  1. 按钮点击事件
  2. 拖拽事件
  3. onScoll
  4. 计算鼠标移动的距离(mousemove)
/**
 * 定时器版
 * @param {Function} fn 需要执行的函数
 * @param {Number} delay 触发时间间隔
 */
function throttle (fn, wait) {
  let timeout = null
  return function () {
    let context = this,
      args = arguments
    if (!timeout) {
      timeout = setTimeout(() => {
        timeout = null
        fn.call(context, args)
      }, wait)
    }
  }
}

/**
 *时间戳版
 * @param {Function} fn 需要执行的函数
 * @param {Number} wait 触发时间间隔
 */
function throttle (fn, wait) {
  let pre = 0
  return function () {
    let now = Date.now(),
      context = this,
      args = arguments
    if (now - pre > wait) {
      fn.call(context, args)
      pre = now
    }

  }
}

var、let、const区别

声明方式 变量提升 暂时性死区 重复声明 块作用域有效 初始值 重新赋值
var 不存在 允许 不是 不必须 允许
let 不会 存在 不允许 不必须 允许
const 不会 存在 不允许 必须 不允许

作用域中声明了let变量,但是let变量的使用却在声明之前,这通常叫做变量提升。
但是let并不像var一样,var变量声明前使用,会打印出undefined.但是let变量直到被赋值才会被初始化。
在变量被初始化前访问这个变量会报reference error.我们称这个变量在作用域开始到被初始化之间为暂时性死区。 

  1. var存在变量提升,let,const都不存在变量提升 
  2. 暂时性死区
  3. 在相同作用域中,let 和 const 不允许重复声明变量,var允许重复声明变量
  4. const声明变量时必须设置初始值
  5. const声明一个只读常量,这个常量不可改变
  6. let/const 声明的变量仅在块级作用域中有效。而 var 声明的变量在块级作用域外仍能访问到。

用var声明for循环变量:

用let声明for循环变量::

我们说 let 声明的变量仅在块级作用域内有效,变量i是let声明的,当前的 i 只在本轮循环有效,所以每一次循环的 i 其实都是一个新的变量。

猜你喜欢

转载自blog.csdn.net/weixin_38199437/article/details/93538417