前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript 手写面试题(一)

JavaScript 手写面试题(一)

作者头像
用户8087287
发布2022-10-31 15:31:07
2890
发布2022-10-31 15:31:07
举报
文章被收录于专栏:程序员XR

一、防抖:

使用场景:

为了上面这种防止出现这种情况,就必须好好给他防抖了,不然早晚饿死(因为中午不吃)

开玩笑、开玩笑、正题正题。

实际场景,有一个搜索查询的需求,用户在输入框中输入关键字去查询某一条数据,但是由于数据众多,总不能全部返回渲染,一般情况下是返回几十条进行渲染,然后用户输入的时候再去请求服务器查询数据。实现这个功能就要去监听输入框的输入,但是这样做就有一个问题,如果遇到一些搞事的用户(一直按着键盘不放

)就会一直发送请求,然后明天你因为上班敲代码被开除了

所以这时候就应该拿出防抖,防一下,就像这样

诶,这样不管手这么抖,菜都不会少了,也不会饿死了

原理:当持续触发一个事件时,在n秒内,事件没有再次触发,此时才会执行回调;如果n秒内,又触发了事件,就重新计时。

简单点说就是,你吃饭的时候手一直抖,是夹不到菜,只有不抖的那个时候才能夹到

再简单点就是:我叫你去帮我买可乐,然后你一出门我就叫你回来说我要换成雪碧,然后你再出门我再就你回来说我要换成美年达

,一直这样重复,只有当我最终决定买什么的时候,你才去执行帮我买水这件事

这就是防抖

实现:

代码语言:javascript
复制
function debounce() {
// 定义一个 timer 变量记录定时器并清除
  let timer;
  // 使用递归是为了确保每一次调用都是一个单独定时器
  return function () {
   // 如果定时器存在就先清楚
   timer && clearTimeout(timer)
   // 如果500毫秒内没有再次输入或点击则执行定时器里面的方法
   // 否则清除定时器重新定时
    timer = setTimeout(()=>{
      console.log('500毫秒内只执行最后一次')    
    },500)
  }
}

二、节流:

原理:当一个事件在执行的n秒内或当前状态为false时,不管怎么去触发都不会再次执行该事件,只有在n秒后或当前状态为true时才可再次执行。

简单点就是:我叫你去帮我买可乐,然后你一出门我就叫你回来说我要换成雪碧,然后你再出门我再就你回来说我要换成美年达

,一直这样重复,只有当我最终决定买什么的时候,你才去执行帮我买水这件事

这就是防抖,不管我怎么叫,诶,你就是听不见不回来,只有等你回来才能叫你重新去给我换美年达

实现:

代码语言:javascript
复制
// 方式一:
function throttle(func) {
  // 定义一个 timer 变量记录定时器并清除
  let timer;
  // 记录状态
  let flag = true;
  // 使用递归是为了确保每一次调用都是一个单独定时器
  return function () {
   if(flag) {
      flag = false
      console.log('500毫秒后可以执行下一次')
      timer = setTimeout(()=>{
        flag = true
        timer && clearTimeout(timer)
      },500)
   }
  }
}

// 方式二:
function throttle(diff=500) {
  // 当前时间
  let now = Date.now();
  // 使用递归是为了确保每一次调用都是一个单独定时器
  return function () {
  const end = Date.now()
   if(end - now > diff) {
      now = end
      console.log('500毫秒后可以执行下一次')
   }
  }
}

函数防抖:

将几次操作合并为一次操作进行。原理是维护一个定时器,规定在延迟时间后触发函数,只有最后一次操作能被触发。

函数节流:

使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。

应用场景:

防抖:

1、search联想搜索,用户在不断输入内容的时候,用防抖来节约请求资源。

2、window触发resize时候,不断调整浏览器窗口大小会不断的触发这个事件,用防抖让其只触发一次。

节流:鼠标不断点击(mousedown)触发,让其单位时间内只触发一次。

监听滚动事件,滑到底部自动加载更多。

三、深拷贝:

深拷贝也可以称为深度克隆一个对象,为什么要有深拷贝呢?因为当我们将对象a直接赋值给对象b时,由于对象(数组也是一个对象)是引用数据类型,所以把对象a赋值给对象b时,变量a仅仅是对这个对象的引用,它们指向同一个引用地址,所以在修改a的值时b的值也会发生变化,即:

代码语言:javascript
复制
const a = {
    k1: 1,
    k2: 2
}
// 将 a 直接赋值给 b ===> 浅拷贝
const b = a
a.k1 = 5
console.log(a) // {k1: 5, k2: 2}
console.log(b) // {k1: 5, k2: 2}

为了解决上面的问题,就可以采用深拷贝进行实现,下面来实现一下

实现:

代码语言:javascript
复制
function deepClone(data) {
// 因为对象里面可能还有对象,所以需要使用到递归,这里就要写递归的退出条件
  // 如果对象不存在或者是基本类型,直接返回
  if(data === null || typeof data !== 'object') return data
  // 如果时日期类型就新建日期并返回
  if(data instanceof Date) return new Date(data)
  // 如果时日期类型就新建正则并返回
  if(data instanceof RegExp) return new RegExp(data)
  // 否则,就是对象({} || [] )
  // 接下来我们可以使用 Object.prototype.toString 判断是数组还是Object
  // 然后创建 对应的变量
  // 方式一:
  // let cloneObj;
  // const toString = Object.prototype.toString
  // if(toString .call(data) === '[object Object]') {
  //   cloneObj = {}
  // }else {
  //   cloneObj = []
  // }
  // 方式二:
 // 通过 对象原型上的 constructor 方法,就能够直接获取当前对象的初始值
 let cloneObj = new constructor()
 for (const key in data) {
  // 为了防止访问到原型上的属性,所以采用 hasOwnPrototype 判断一下 
        if (Object.hasOwnProperty.call(data, key)) {
          const el= object[key];
          cloneObj = deepClone(el)
        }
      } 
}

当然了,除了上面的这个方法,还有其他的解决方法,例如:

代码语言:javascript
复制
const a = {
    k1: 1,
    k2: 2
}
// 将 a 直接赋值给 b ===> 浅拷贝
const b = JSON.parse(JSON.stringify(a))
a.k1 = 5
console.log(a) // {k1: 5, k2: 2}
console.log(b) // {k1: 1, k2: 2}

先通过 a 对象通过 JSON.stringify 将其转换成字符串,因为字符串是基本数据类型,所以可以直接赋值,然后在使用 JSON.parse 将其转成对象,由基本数据类型转成引用数据类型会在内存开辟新的空间,所以他们的引用地址就不一样了,不一样就不会相互影响了。

好了以上就是本期内容了!!!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员XR 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档