当前位置: 首页 > news >正文

JS进阶学习04

一、深浅拷贝

1.浅拷贝

首先浅拷贝和深拷贝只针对引用类型

浅拷贝:拷贝的是地址

常见方法:

1. 拷贝对象:Object.assgin() / 展开运算符 {...obj} 拷贝对象
2. 拷贝数组:Array.prototype.concat() 或者 [...arr]

>如果是简单数据类型拷贝值,引用数据类型拷贝的是地址 (简单理解: 如果是单层对象,没问题,如果有多层就有问题)

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script>const obj = {uname: "pink",age: 18,family: {baby: "小pink",},};// 浅拷贝// const o = { ...obj };// console.log(o); //Object { uname: "pink", age: 18, family: {…} }// o.age = 20;// console.log(o); //Object { uname: "pink", age: 20, family: {…} }// console.log(obj); //Object { uname: "pink", age: 18, family: {…} }const o = {};Object.assign(o, obj);o.age = 20;o.family.baby = "老pink";console.log(o); //Object { uname: "pink", age: 20, family: {…} }console.log(obj); //Object { uname: "pink", age: 18, family: {…} }</script></body>
</html>

2.深拷贝

首先浅拷贝和深拷贝只针对引用类型
深拷贝:拷贝的是对象,不是地址
常见方法:
1. 通过递归实现深拷贝
2. lodash/cloneDeep
3. 通过JSON.stringify()实现

(1)函数递归

函数递归:
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
·简单理解:函数内部自己调用自己, 这个函数就是递归函数
·递归函数的作用和循环效果类似
· 由于递归很容易发生“栈溢出”错误(stack overflow),所以 必须要加退出条件 return
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><script>const obj = {uname: 'pink',age: 18,hobby: ['乒乓球', '足球'],family: {baby: '小pink'}}const o = {}// 拷贝函数function deepCopy(newObj, oldObj) {debuggerfor (let k in oldObj) {// 处理数组的问题  一定先写数组 在写 对象 不能颠倒if (oldObj[k] instanceof Array) {newObj[k] = []//  newObj[k] 接收 []  hobby//  oldObj[k]   ['乒乓球', '足球']deepCopy(newObj[k], oldObj[k])} else if (oldObj[k] instanceof Object) {newObj[k] = {}deepCopy(newObj[k], oldObj[k])}else {//  k  属性名 uname age    oldObj[k]  属性值  18// newObj[k]  === o.uname  给新对象添加属性newObj[k] = oldObj[k]}}}deepCopy(o, obj) // 函数调用  两个参数 o 新对象  obj 旧对象console.log(o)o.age = 20o.hobby[0] = '篮球'o.family.baby = '老pink'console.log(obj)console.log([1, 23] instanceof Object)// 复习// const obj = {//   uname: 'pink',//   age: 18,//   hobby: ['乒乓球', '足球']// }// function deepCopy({ }, oldObj) {//   // k 属性名  oldObj[k] 属性值//   for (let k in oldObj) {//     // 处理数组的问题   k 变量//     newObj[k] = oldObj[k]//     // o.uname = 'pink'//     // newObj.k  = 'pink'//   }// }</script>
</body></html>

(2)lodash

js库lodash里面cloneDeep内部实现了深拷贝

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><!-- 先引用 --><script src="./lodash.min.js"></script><script>const obj = {uname: "pink",age: 18,hobby: ["乒乓球", "足球"],family: {baby: "小pink",},};const o = _.cloneDeep(obj);console.log(o); //Object { uname: "pink", age: 18, hobby: (2) […], family: Object { baby: "老pink" } }o.family.baby = "老pink";console.log(obj); //Object { uname: "pink", age: 18, hobby: (2) […], family: Object { baby: "小pink" } }</script></body>
</html>

(3)JSON.stringify()

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script>const obj = {uname: "pink",age: 18,hobby: ["乒乓球", "足球"],family: {baby: "小pink",},};// 把对象转换为 JSON 字符串// console.log(JSON.stringify(obj))const o = JSON.parse(JSON.stringify(obj));console.log(o); //Object { uname: "pink", age: 18, hobby: Array [ "乒乓球", "足球" ], family: {Object { baby: "123" }} }o.family.baby = "123";console.log(obj); //Object { uname: "pink", age: 18, hobby: Array [ "乒乓球", "足球" ], family: Object { baby: "小pink" } }</script></body>
</html>

二、异常处理

1.throw抛异常

2.try/catch捕获异常

3.debugger

相当于断点调试

三、处理this

1.this指向

(1)普通函数

普通函数的调用方式决定了 this 的值,即【谁调用 this 的值指向谁】  

 

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><button>点击</button><script>// 普通函数:  谁调用我,this就指向谁console.log(this)  // windowfunction fn() {console.log(this)  // window    }window.fn()window.setTimeout(function () {console.log(this) // window }, 1000)document.querySelector('button').addEventListener('click', function () {console.log(this)  // 指向 button})const obj = {sayHi: function () {console.log(this)  // 指向 obj}}obj.sayHi()</script>
</body></html>

 (2)箭头函数

<script>console.log(this); // 此处为 window// 普通函数const sayHi = function () {console.log(this);};// 普通对象const user = {name: "小明",// 该箭头函数中的 this 为函数声明环境中 this 一致walk: () => {console.log(this);},sleep: function () {let str = "hello";console.log(this);let fn = () => {console.log(str);console.log(this); // 该箭头函数中的 this 与 sleep 中的 this 一致};// 调用箭头函数fn();},};// 动态添加方法user.sayHi = sayHi;// 函数调用// user.sayHi();// this指的是user// Object { name: "小明", walk: walk(), sleep: sleep(), sayHi: sayHi() }// user.sleep();// this指的是user(普通函数)// Object { name: "小明", walk: walk(), sleep: sleep(), sayHi: sayHi() }// hello// Object { name: "小明", walk: walk(), sleep: sleep(), sayHi: sayHi() }user.walk();// this指的是window(箭头函数)// Window// Window
</script>

 

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><button class="btn">点击</button><script></script></body><script>// DOM 节点const btn = document.querySelector(".btn");// 箭头函数 此时 this 指向了 windowbtn.addEventListener("click", () => {console.log(this); //Window});// 普通函数 此时 this 指向了 DOM 对象btn.addEventListener("click", function () {console.log(this);//<button class="btn">});</script>
</html>

2.改变this

(1)call()- this指向传入的参数

 

(2)apply()-传入必须是数组,this指向数组

(3)bind()-不会调用函数,但改变this

(4)总结- important

四、性能优化 (重要)

1.防抖

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间

 实现方式

(1)lodash提供的防抖来处理

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>.box {width: 500px;height: 500px;background-color: #ccc;color: #fff;text-align: center;font-size: 100px;}</style>
</head><body><div class="box"></div><script src="./lodash.min.js"></script><script>const box = document.querySelector('.box')let i = 1  // 让这个变量++// 鼠标移动函数function mouseMove() {box.innerHTML = ++i// 如果里面存在大量操作 dom 的情况,可能会卡顿}// 添加事件// box.addEventListener('mousemove', mouseMove)// lodash 防抖的写法 - 500ms后加一// 语法:_.debounce(fun,时间)box.addEventListener('mousemove', _.debounce(mouseMove, 500))</script>
</body></html>

(2)手写一个防抖函数来处理

手写防抖函数

核心是利用setTimeout()定时器来实现

1.声明定时器变量

2.每次鼠标移动(时间触发)的时候都要先判断是否有定时器,如果有先清除以前的定时器

3.如果没有定时器,则开启定时器,存入到定时器变量里面。

4.定时器里面写函数调用

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>.box {width: 500px;height: 500px;background-color: #ccc;color: #fff;text-align: center;font-size: 100px;}</style>
</head><body><div class="box"></div><script>const box = document.querySelector('.box')let i = 1  // 让这个变量++// 鼠标移动函数function mouseMove() {box.innerHTML = ++i// 如果里面存在大量操作 dom 的情况,可能会卡顿}// 防抖函数function debounce(fn, t) {let timeIdreturn function () {// 如果有定时器就清除if (timeId) clearTimeout(timeId)// 开启定时器 200timeId = setTimeout(function () {fn()}, t)}}// box.addEventListener('mousemove', mouseMove)box.addEventListener('mousemove', debounce(mouseMove, 200))</script>
</body></html>

2.节流

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。

(1) lodash函数

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>.box {width: 500px;height: 500px;background-color: #ccc;color: #fff;text-align: center;font-size: 100px;}</style></head><body><div class="box"></div><script src="./lodash.min.js"></script><script>const box = document.querySelector(".box");let i = 1; // 让这个变量++// 鼠标移动函数function mouseMove() {box.innerHTML = ++i;// 如果里面存在大量操作 dom 的情况,可能会卡顿}// box.addEventListener('mousemove', mouseMove)// lodash 节流写法box.addEventListener("mousemove", _.throttle(mouseMove, 500));</script></body>
</html>

(2)手写一个节流函数

手写一个节流函数- 每隔 500ms + 1

节流的核心就是利用定时器(setTimeout)来实现

1.声明一个定时器变量

2.当鼠标每次滑动都先判断是否有定时器了,如果有定时器则不开启新定时器

3.如果没有定时器则开启定时器,记得存到变量里面

3.1 定时器里面调用执行的函数

3.2定时器里面要把定时器清空

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>.box {width: 500px;height: 500px;background-color: #ccc;color: #fff;text-align: center;font-size: 100px;}</style></head><body><div class="box"></div><script>const box = document.querySelector(".box");let i = 1; // 让这个变量++// 鼠标移动函数function mouseMove() {box.innerHTML = ++i;// 如果里面存在大量操作 dom 的情况,可能会卡顿}// 手写一个节流函数- 每隔 500ms + 1// 节流的核心就是利用定时器(setTimeout)来实现// 1.声明一个定时器变量// 2.当鼠标每次滑动都先判断是否有定时器了,如果有定时器则不开启新定时器// 3.如果没有定时器则开启定时器,记得存到变量里面// 3.1 定时器里面调用执行的函数// 3.2定时器里面要把定时器清空// 节流函数function throttle(fn, t) {let timeId = null;return function () {if (!timeId) {timeId = setTimeout(function () {fn();// 清空定时器timeId = null;// 不用clearTimeout() // 原因:在setTimeout中是无法删除定时器多,因为定时器还在运作,所以使用timer=null 而不是clearTimeout(timer)}, t);}};}// box.addEventListener('mousemove', mouseMove)box.addEventListener("mousemove", throttle(mouseMove, 200));</script></body>
</html>

 3.总结

 

相关文章:

  • 26、AI 预测性维护 (燃气轮机轴承) - /安全与维护组件/ai-predictive-maintenance-turbine
  • python查询elasticsearch 获取指定字段的值的list
  • 安卓蓝牙frameworks/base/core/java/android/bluetooth这个路径下文件的作用
  • java day14
  • [Java恶补day2] 49. 字母异位词分组
  • 深入理解 Pre-LayerNorm :让 Transformer 训练更稳
  • Java虚拟机栈
  • leetcode hot100刷题日记——7.最大子数组和
  • 计算机视觉与深度学习 | Python实现CEEMDAN-ISOS-VMD-GRU-ARIMA时间序列预测(完整源码和数据)
  • 目标检测基础知识
  • 目标检测135个前沿算法模型汇总(附源码)!
  • vue项目启动报错(node版本与Webpack)
  • vue-cli 构建打包优化(JeecgBoot-Vue2 配置优化篇)
  • MEMO数据DID与ZK技术:赋能RWA代币化与可信流通的新基石
  • C++ 01.vscode配置c++开发环境
  • C++语法理解记录
  • 安卓开发用到的设计模式(1)创建型模式
  • 缺乏经验的 PCB 过孔建模方法
  • NIFI的处理器:JSLTTransformJSON 2.4.0
  • 基于LiveData和ViewModel的路线管理实现(带PopupWindow删除功能)
  • 做拼货商城网站/企业网络营销推广方案策划
  • wordpress rds/南京网络优化公司有哪些
  • 智慧团建登录入口官网/志鸿优化设计电子版