JS面试题

166 阅读4分钟

防抖(debounce)

定义:设置单位时间内,触发高频事件后,函数只会执行一次。如果单位时间内事件再次触发事件,将其延迟,重新计算时间。

防抖:回城时,被打断,就要重新来。

1.简单实现防抖功能

function debounce(fn, wait) {
  let timer = null
  return function (...args) {
    clearTimeout(timer)
    timer = setTimeout(function () {
      fn()
    }, wait)
  }
}

window.onresize = debounce(function () {
  console.log('onresize')
}, 1000)

2.参数传递和this指向绑定

function debounce(fn, wait) {
  let timer = null
  return function (...args) {
    clearTimeout(timer)
    let context = this
    timer = setTimeout(function () {
      fn.apply(context, args)
    }, wait)
  }
}

window.onresize = debounce(function () {
  console.log('onresize', this)
}, 1000)

防止抖动,单位时间内事件触发会被重置,避免事件被误伤触发多次。代码实现重在清零 clearTimeout,this 必须指向调用它的对象。防抖可以比作等电梯,只要有一个人进来,就需要再等一会儿。

应用场景:

  • 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖。

  • 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖。

  • input 框实时搜索,展示联想内容。

节流(throttle)

定义:节流函数用于限制函数的执行频率,在指定的时间间隔内,只允许函数执行一次。

节流:技能CD,技能CD未结束,无法使用技能。

1.使用时间戳

function throttle(fn, wait) {
  let time = 0
  return function (...args) {
    let nowTime = Date.now()
    let context = this
    if (time - now > wait) {
      fn.apply(context, args)
      time = nowTime
    }
  }
}

window.onresize = throttle(function () {
  console.log('onresize')
}, 300)

代码中的节流函数接受两个参数:fn和wait。fn是需要被节流的函数,wait是时间间隔的阈值。节流函数返回一个新的函数,在新函数中会对时间间隔进行判断。每当新函数被调用时,它会获取当前的时间戳(nowTime),并与上一次执行函数的时间戳(time)进行比较。如果两个时间戳的差值大于等于设定的时间间隔wait),则会执行传入的函数(fn)。更新时间戳为当前的时间(nowTime)在最后的代码中,将节流函数应用于window对象的onresize事件处理程序。每当浏览器窗口发生变化时,如果两次resize事件的时间间隔大于等于300毫秒,则会打印"onresize"。这样就能实现在指定的时间间隔内,限制onresize事件的触发频率,避免过多的执行。

通过 let context = this 将函数绑定的执行环境保存下来的。这是因为在返回的新函数中,由于闭包的特性,原始的函数,将不再拥有正确的执行上下文。为了保持始函数在正确的上下文中执行,我们将其保存到局部变量context中,并在调用fn时使用fn.apply(context, args)的方式来保证函数执行时的上下文正确。 这种保存和应用上下文的方式在 JavaScript 中经常用于确保函数在正确的对象上下文中运行,尤其在事件处理函数等回调函数中,以确保函数中的this关键字指向期望的对象。

应用场景:

  • scroll 事件,每隔一秒计算一次位置信息等。
  • 浏览器播放事件,每个一秒计算一次进度信息等。

关于 JSON,以下代码输出什么

const obj = {
  a: 1,
  b: 2,
  c: null,
  d: undefined,
  get e() {},
  f: Symbol()
}

console.log(JSON.stringify(obj))

答案:

{"a":1,"b":2,"c":null}

使用JSON.stringify()方法,undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略。

什么是类数组?以及如何转化为数组?

在JavaScript中,类数组(array-like object)是指:具有长度(length)属性和按索引访问元素的对象,但没有数组原型上的方法(例如push和forEach)。

  1. 常见的类数组:
  • arguments 对象
  • DOM 元素集合对象
  • 字符串
  1. 将类数组,转换为真正的数组。
  • Array.from()方法:

    const arrayLike = { 0: 'apple', 1: 'banana', 2: 'orange', length: 3 };
    const array = Array.from(arrayLike);
    console.log(array); // ['apple', 'banana', 'orange']
    
  • Array.prototype.slice.call()方法:

    const arrayLike = { 0: 'apple', 1: 'banana', 2: 'orange', length: 3 };
    const array = Array.prototype.slice.call(arrayLike);
    console.log(array); // ['apple', 'banana', 'orange']
    

Array(100).map(x => 1) 输出的结果是?

const array = Array(100).map(x => 1)
console.log(array) 

答案:[empty × 100]

解析:Array(100) 的值为 [empty × 100] 的稀疏数组,map() 方法的callbackFn 仅在已分配值的数组索引处被调用,它不会在稀疏数组中的空槽处被调用。

那么如何让数组的每个元素都为1?

const arr = Array(100).fill(1)