day25--JS进阶(递归函数,深浅拷贝,异常处理,改变this指向,防抖及节流)

目录

浅拷贝

[1.拷贝对象①Object.assgin() ②展开运算符newObj = {...obj}拷贝对象](#1.拷贝对象①Object.assgin() ②展开运算符newObj = {...obj}拷贝对象)

[2.拷贝数组 ①Array.prototype.concat() ② newArr = [...arr]](#2.拷贝数组 ①Array.prototype.concat() ② newArr = [...arr])

深拷贝

1.通过递归实现深拷贝

2.lodash/cloneDeep实现

3.通过JSON.stringify()实现

异常处理

throw抛异常

try/catch捕获异常

debugger

处理this

this指向

普通函数this指向

箭头函数this指向

改变this

call()

apply()

bind()

性能优化

防抖

[1. lodash提供的防抖函数来处理](#1. lodash提供的防抖函数来处理)

[2. 手写一个防抖函数来处理](#2. 手写一个防抖函数来处理)

节流

[1. lodash提供的节流函数来处理](#1. lodash提供的节流函数来处理)

[2. 手写一个节流函数来处理](#2. 手写一个节流函数来处理)


浅拷贝

关于对象/数组等引用数据类型直接复制出现的问题:

因为复制完后的是地址,因此修改复制后的会影响到原来的对象

需要深浅拷贝来解决。

1.拷贝对象①Object.assgin() ②展开运算符newObj = {...obj}拷贝对象

2.拷贝数组 ①Array.prototype.concat() ② newArr = [...arr]

Array.prototype.concat()

concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

因此用于拷贝,则先声明一个空数组再对其进行拷贝。

利用浅拷贝,遇到简单的引用数据类型可以,只是拷贝最外边一层,但是里层的仍然是拷贝地址!

因此,对于浅拷贝,对于多层会出现原本出现的问题,对于多层对象/数组,需要深拷贝。

深拷贝

1.通过递归实现深拷贝

深拷贝需要用到函数递归;如果遇到数组,利用递归处理;如果遇到对象,利用递归处理,二者顺序不可调换

javascript 复制代码
// 深拷贝函数
    function deepCopy(newObj, oldObj) {
      // 遍历旧对象
      for (let k in oldObj) {
        // 遇到值为数组的处理
        if (oldObj[k] instanceof Array) {
          // 如果值为数组,则要对该属性遍历,先要有一个空数组
          newObj[k] = []
          deepCopy(newObj[k], oldObj[k])
        } else if (oldObj[k] instanceof Object) {
          // 如果值为对象,则要对该属性遍历,先要有一个空对象
          newObj[k] = {}
          deepCopy(newObj[k], oldObj[k])
        } else {
          newObj[k] = oldObj[k]
        }

      }
    }

    deepCopy(o, obj)

2.lodash/cloneDeep实现

要先引入库

<script src="./lodash.min.js"></script>

3.通过JSON.stringify()实现

转为JSON字符串再进行拷贝

异常处理

throw抛异常

主观上在适当的地方抛出想设置的异常提示语

try/catch捕获异常

语法:try{} catch(err){} [finally{}]

\]表示可选 ![](https://file.jishuzhan.net/article/1711030982263443457/575b38b40191ff26b56a0dd2e13d15cd.webp) ![](https://file.jishuzhan.net/article/1711030982263443457/b79ea56d30c7b844a87f2c3b5358631a.webp) catch(err){} 是获取到错误信息对象,上述是将错误信息打印出来。catch(){}不会终止函数,需要手动进行return ![](https://file.jishuzhan.net/article/1711030982263443457/bfe83de47ec803366fd335cd8adf08b6.webp) #### debugger debugger 代码中打断点,效果与在浏览器中同,只是有时更方便。 ### 处理this #### this指向 ##### 普通函数this指向 普通函数的this指向调用者 ##### 箭头函数this指向 逐层往外层函数一层层找,直至有this的定义 ![](https://file.jishuzhan.net/article/1711030982263443457/350f30cfe9e84c5a83815ba151755fc0.webp) #### 改变this 后两者更重要 ![](https://file.jishuzhan.net/article/1711030982263443457/1a22ec7e9a5a8dcb3045d388b092a541.webp) ##### call() 调用函数,同时改变函数中的this指向 ![](https://file.jishuzhan.net/article/1711030982263443457/eb5effbfa965362264307245ecc8f112.webp)![](https://file.jishuzhan.net/article/1711030982263443457/2972957df1d92fa613ca253d4b9049ab.webp) ##### apply() 与call()的不同点在于传递的函数形参要用数组包裹着 ![](https://file.jishuzhan.net/article/1711030982263443457/98cba362d1ded442bde9f362a9e0ca00.webp) ![](https://file.jishuzhan.net/article/1711030982263443457/dc1440b17caaf92ca1238e39b70a0a3f.webp) ##### bind() 与前两者不同的是 其能改变this指向但!!不会调用函数 因为不调用函数,因此返回值并不是函数返回值,而是拷贝出来的原函数(新函数) **因此只是想改变this指向而不想立马调用函数时要首先想到bind()!!!** ![](https://file.jishuzhan.net/article/1711030982263443457/03ab50168a95e391956a06c3b18c5b2c.webp) ![](https://file.jishuzhan.net/article/1711030982263443457/f5a0c9347d7123e31d7abc71be57ff13.webp) → ![](https://file.jishuzhan.net/article/1711030982263443457/ecdc24aecb5900512b7af02a9272cb81.webp) ![](https://file.jishuzhan.net/article/1711030982263443457/0922bf3b57003f31e7b02457a40f0069.webp) ### 性能优化 一般对于触发频次比较高的时间,就需要用防抖或者节流函数来控制触发。 #### 防抖 ![](https://file.jishuzhan.net/article/1711030982263443457/2beb1a6626de5a379b20194e2a8823e2.webp) ![](https://file.jishuzhan.net/article/1711030982263443457/6404e150c152d4a86c9a3983f278e2b0.webp) ##### 1. lodash提供的防抖函数来处理 (其是个函数!) ![](https://file.jishuzhan.net/article/1711030982263443457/d7bd555b247c210ff5f2d72af5c97af5.webp) ![](https://file.jishuzhan.net/article/1711030982263443457/6ffc1df9805523c0ed7ca77ed75a49e3.webp) ##### 2. 手写一个防抖函数来处理 ![](https://file.jishuzhan.net/article/1711030982263443457/96c10c8cb5ddc1a2c42a6fdd24f73b4f.webp) ```javascript function debounce(fn, t) { let Time console.log(Time) return function () { if (Time) clearTimeout(Time) Time = setTimeout(fn, t) } } ``` #### 节流 ![](https://file.jishuzhan.net/article/1711030982263443457/b9fd6bf0a77d2e07a3519841b737d124.webp) ![](https://file.jishuzhan.net/article/1711030982263443457/952b9baec557a6619c8f477ecd1a1974.webp) ![](https://file.jishuzhan.net/article/1711030982263443457/2a76d52aacf8649711fec2a018ead4ae.webp) ##### 1. lodash提供的节流函数来处理 这个节流函数是指单位时间内只触发一次,如果单位时间内被触发了多次,在第一次触发结束时会被触发第二次,但不会有第三次,第四次....尽管前面触发了多次。 与手写的节流有不同,手写的节流是单位时间在最后一刻触发,且单位时间内触发了多次,仍然是最后一刻触发。 用法与上同 ![](https://file.jishuzhan.net/article/1711030982263443457/74221f939129bfd04dbc884f78088baa.webp) ##### 2. 手写一个节流函数来处理 ```javascript function throttle(fn, t) { let timer return function () { // 如果没有定时器运行,则开启,开启后清空, // 如果有,则不开启 console.log(timer) if (!timer) { timer = setTimeout(function () { fn() // 开启后执行完后清掉定时器(将定时器置为空),确保下一次正常执行 // 置空一定要放在定时器内部 timer = null }, t) } } } ```

相关推荐
じ☆ve 清风°6 分钟前
滑动窗口算法详解与C++实现
开发语言·c++·算法
繁依Fanyi7 分钟前
用 UniApp 构建习惯打卡 App —— HabitLoop 开发记
javascript·uni-app·codebuddy首席试玩官
东锋1.310 分钟前
前端动画库 Anime.js 的V4 版本,兼容 Vue、React
前端·javascript·vue.js
苕皮蓝牙土豆11 分钟前
C++ map & multimap 容器:赋值、排序、大小与删除操作
开发语言·c++
Villiam_AY18 分钟前
Go 后端中双 token 的实现模板
开发语言·后端·golang
DjangoJason24 分钟前
计算机网络 : Socket编程
linux·服务器·开发语言·笔记·计算机网络
映秀小子27 分钟前
C语言链表的操作
c语言·开发语言·链表
救救孩子把40 分钟前
Mac 环境下 JDK 版本切换全指南
java·开发语言·macos
我们的五年44 分钟前
【Qt】Qt常见控件的相关知识点
开发语言·qt
孙同学_1 小时前
【C++】map和set的使用
开发语言·c++