Javascript中的深浅拷贝以及实现方法

目录

一、前言

二、深浅拷贝

1、浅拷贝

2、深拷贝

三、递归实现深拷贝

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

2、Json序列化

四、异常处理

throw

try ... catch

debugger

五、处理this

普通函数

箭头函数

六、改变this指向

call

apply

bind

七、防抖节流


一、前言

  在 JavaScript 中,"拷贝"是指将一个对象的值复制到另一个对象中。虽然这看起来是一个简单的操作,但在实际开发中,浅拷贝和深拷贝的区别可能会引发许多意想不到的错误或性能问题。因此,理解这两者的概念及其适用场景对于开发者来说至关重要。

二、深浅拷贝

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

1、浅拷贝

浅拷贝拷贝的是地址

常见方法:

  1. 拷贝对象:Object.assgin() / 展开运算符 {...obj} 拷贝对象

  2. 拷贝数组:Array.prototype.concat() 或者 [...arr]

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

2、深拷贝

深拷贝拷贝的对象,不是地址

常见方法:

  1. 通过递归实现深拷贝

  2. lodash/cloneDeep

  3. 通过JSON.stringify()实现

三、递归实现深拷贝

1、函数递归:

如果一个函数在内部可以调用其本身,那么这个函数就是递归函数

  • 简单理解:函数内部自己调用自己, 这个函数就是递归函数

  • 递归函数的作用和循环效果类似

  • 由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件 return

<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>

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

<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)o.family.baby = '老pink'console.log(obj)</script>
</body>

2、Json序列化

<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)o.family.baby = '123'console.log(obj)</script>
</body>

四、异常处理

了解 JavaScript 中程序异常处理的方法,提升代码运行的健壮性。

throw

异常处理是指预估代码执行过程中可能发生的错误,然后最大程度的避免错误的发生导致整个程序无法继续运行

总结:

  1. throw 抛出异常信息,程序也会终止执行

  2. throw 后面跟的是错误提示信息

  3. Error 对象配合 throw 使用,能够设置更详细的错误信息

<script>function counter(x, y) {if(!x || !y) {// throw '参数不能为空!';throw new Error('参数不能为空!')}return x + y}counter()
</script>

总结:

  1. throw 抛出异常信息,程序也会终止执行

  2. throw 后面跟的是错误提示信息

  3. Error 对象配合 throw 使用,能够设置更详细的错误信息

try ... catch

<script>function foo() {try {// 查找 DOM 节点const p = document.querySelector('.p')p.style.color = 'red'} catch (error) {// try 代码段中执行有错误时,会执行 catch 代码段// 查看错误信息console.log(error.message)// 终止代码继续执行return}finally {alert('执行')}console.log('如果出现错误,我的语句不会执行')}foo()
</script>

总结:

  1. try...catch 用于捕获错误信息

  2. 将预估可能发生错误的代码写在 try 代码段中

  3. 如果 try 代码段中出现错误后,会执行 catch 代码段,并截获到错误信息

debugger

相当于断点调试

五、处理this

了解函数中 this 在不同场景下的默认值,知道动态指定函数 this 值的方法。

this 是 JavaScript 最具“魅惑”的知识点,不同的应用场合 this 的取值可能会有意想不到的结果,在此我们对以往学习过的关于【 this 默认的取值】情况进行归纳和总结。  

普通函数

普通函数的调用方式决定了 this 的值,即【谁调用 this 的值指向谁】,如下代码所示:

<script>// 普通函数function sayHi() {console.log(this)  }// 函数表达式const sayHello = function () {console.log(this)}// 函数的调用方式决定了 this 的值sayHi() // windowwindow.sayHi()// 普通对象const user = {name: '小明',walk: function () {console.log(this)}}// 动态为 user 添加方法user.sayHi = sayHiuesr.sayHello = sayHello// 函数调用方式,决定了 this 的值user.sayHi()user.sayHello()
</script>

注: 普通函数没有明确调用者时 this 值为 window,严格模式下没有调用者时 this 的值为 undefined。  

箭头函数

箭头函数中的 this 与普通函数完全不同,也不受调用方式的影响,事实上箭头函数中并不存在 this !箭头函数中访问的 this 不过是箭头函数所在作用域的 this 变量。

<script>console.log(this) // 此处为 window// 箭头函数const sayHi = function() {console.log(this) // 该箭头函数中的 this 为函数声明环境中 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()user.sleep()user.walk()
</script>

在开发中【使用箭头函数前需要考虑函数中 this 的值】,事件回调函数使用箭头函数时,this 为全局的 window,因此DOM事件回调函数不推荐使用箭头函数,如下代码所示:

<script>// DOM 节点const btn = document.querySelector('.btn')// 箭头函数 此时 this 指向了 windowbtn.addEventListener('click', () => {console.log(this)})// 普通函数 此时 this 指向了 DOM 对象btn.addEventListener('click', function () {console.log(this)})
</script>

同样由于箭头函数 this 的原因,基于原型的面向对象也不推荐采用箭头函数,如下代码所示:

<script>function Person() {}// 原型对像上添加了箭头函数Person.prototype.walk = () => {console.log('人都要走路...')console.log(this); // window}const p1 = new Person()p1.walk()
</script>

六、改变this指向

以上归纳了普通函数和箭头函数中关于 this 默认值的情形,不仅如此 JavaScript 中还允许指定函数中 this 的指向,有 3 个方法可以动态指定普通函数中 this 的指向:

call

使用 call 方法调用函数,同时指定函数中 this 的值,使用方法如下代码所示:

<script>// 普通函数function sayHi() {console.log(this);}let user = {name: '小明',age: 18}let student = {name: '小红',age: 16}// 调用函数并指定 this 的值sayHi.call(user); // this 值为 usersayHi.call(student); // this 值为 student// 求和函数function counter(x, y) {return x + y;}// 调用 counter 函数,并传入参数let result = counter.call(null, 5, 10);console.log(result);
</script>

总结:

  1. call 方法能够在调用函数的同时指定 this 的值

  2. 使用 call 方法调用函数时,第1个参数为 this 指定的值

  3. call 方法的其余参数会依次自动传入函数做为函数的参数

apply

使用 call 方法调用函数,同时指定函数中 this 的值,使用方法如下代码所示:

<script>// 普通函数function sayHi() {console.log(this)}let user = {name: '小明',age: 18}let student = {name: '小红',age: 16}// 调用函数并指定 this 的值sayHi.apply(user) // this 值为 usersayHi.apply(student) // this 值为 student// 求和函数function counter(x, y) {return x + y}// 调用 counter 函数,并传入参数let result = counter.apply(null, [5, 10])console.log(result)
</script>

总结:

  1. apply 方法能够在调用函数的同时指定 this 的值

  2. 使用 apply 方法调用函数时,第1个参数为 this 指定的值

  3. apply 方法第2个参数为数组,数组的单元值依次自动传入函数做为函数的参数

bind

bind 方法并不会调用函数,而是创建一个指定了 this 值的新函数,使用方法如下代码所示:

<script>// 普通函数function sayHi() {console.log(this)}let user = {name: '小明',age: 18}// 调用 bind 指定 this 的值let sayHello = sayHi.bind(user);// 调用使用 bind 创建的新函数sayHello()
</script>

注:bind 方法创建新的函数,与原函数的唯一的变化是改变了 this 的值。  

七、防抖节流

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/60637.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Tofu AI视频处理模块视频输入配置方法

应用Tofu产品对网络视频进行获取做视频处理时&#xff0c;首先需要配置Tofu产品的硬件连接关系与设备IP地址、视频拉流地址。 步骤1 Tofu设备点对点直连或者通过交换机连接到电脑&#xff0c;电脑IP配置到与Tofu默认IP地址同一个网段。 打开软件 点击右上角系统设置 单击左侧…

QT<30> Qt中使鼠标变为转圈忙状态

前言&#xff1a;当我们在写软件时&#xff0c;在等待阻塞耗时操作时可以将鼠标变为忙状态&#xff0c;并在一段时间后恢复状态&#xff0c;可以用到GxtWaitCursor&#xff1a;Qt下基于RAII的鼠标等待光标类。 一、效果演示 二、详细代码 在项目中添加C文件&#xff0c;命名为…

什么是CRM系统?

越来越多的企业意识到&#xff1a;如何有效管理与客户的关系、提升客户满意度&#xff0c;并通过这些提升推动销售增长&#xff0c;已经成为许多公司亟待解决的问题。为此&#xff0c;客户关系管理&#xff08;Customer Relationship Management&#xff0c;简称CRM&#xff09…

【青牛科技】 GC6153——TMI8152 的不二之选,可应用于摇头机等产品中

在电子工程领域&#xff0c;不断寻求性能更优、成本更低的解决方案是工程师们的永恒追求。今天&#xff0c;我们要为广大电子工程师带来一款极具竞争力的产品 —— GC6153&#xff0c;它将成为 TMI8152 的完美替代之选。 一、产品背景 随着科技的飞速发展&#xff0c;电子设备…

JS 实现游戏流畅移动与按键立即响应

AWSD 按键移动 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.box1 {width: 400px;height: 400px;background: yellowgreen;margin: 0 auto;position: relative;}.box2 {width: 50px;height:…

服务器上安装Orcale数据库以及PL SQL工具(中文)

一、前期准备 1、oracle数据库安装包–>Oracle下载地址&#xff0c;版本根据当时情况就下最新的就行&#xff0c;下载时间可能有点长&#xff0c;耐心点。 2、PL SQL工具下载地址–>PL SQL下载地址&#xff0c;百度网盘可以共享【限速&#xff0c;没办法&#xff01;&am…

javaWeb小白项目--学生宿舍管理系统

目录 一、检查并关闭占用端口的进程 二、修改 Tomcat 的端口配置 三、重新启动 Tomcat 一、javaw.exe的作用 二、结束javaw.exe任务的影响 三、如何判断是否可以结束 结尾&#xff1a; 这个错误提示表明在本地启动 Tomcat v9.0 服务器时遇到了问题&#xff0c;原因是所需…

python爬虫(二)爬取国家博物馆的信息

import requests from bs4 import BeautifulSoup# 起始网址 url https://www.chnmuseum.cn/zx/xingnew/index_1.shtml # 用于存储所有数据 all_data [] page 1 global_index 1 # 定义全局序号变量并初始化为1 while True:html_url requests.get(url).textif requests.get…

2024 年(第 7 届)“泰迪杯”数据分析技能赛B 题 特殊医学用途配方食品数据分析 完整代码 结果 可视化分享

一、背景特殊医学用途配方食品简称特医食品&#xff0c;是指为满足进食受限、消化吸收障碍、代谢素乱或者特定疾病状态人群对营养素或者膳食的特殊需要&#xff0c;专门加工配置而成的配方食品&#xff0c;包括0月龄至12月龄的特殊医学用途婴儿配方食品和适用于1岁以上的特殊医…

TofuAI处理BT1120时序视频要求

时序要求 BT.1120视频用于1920x108030Hz数字视频输入。具体时序必须严格按照说明。BT.1120输入电平为1.8V。 BT1120数字视频采用YCbCr彩色格式输出&#xff0c;串行数据位宽为16bit&#xff0c;亮度在 高8bit&#xff0c;色度在低8bit&#xff0c;亮度和色度在同一个时钟周期输…

ASP.NET MVC宠物商城系统

该系统采用B/S架构&#xff0c;使用C#编程语言进行开发&#xff0c;以ASP.NET MVC框架为基础&#xff0c;以Visual Studio 2019为开发工具&#xff0c;数据库采用SQL Server进行保存数据。系统主要功能包括登录注册、宠物展示、个人中心、我的订单、购物车、用户管理、宠物类别…

嵌入式硬件实战提升篇(一)-泰山派RK3566制作多功能小手机

引言&#xff1a;主要针对于嵌入式全栈内容的知识点汇总并对于linux等相关驱动知识点进行串联&#xff0c;用大家参考学习&#xff0c;并用到了嘉立创提供的泰山派RK3566作为学习的主控。 实物演示如下所示&#xff1a; 目录 一、硬件设计 1.转接电路 2.背光电路 3.音频接…

玩转ChatGPT:文献阅读 v2.0

一、写在前面 好久不更新咯。 因为最近ChatGPT更新了不少功能&#xff08;水一篇刷存在感&#xff09;&#xff1a; 上线ChatGPT-4o模型&#xff0c;说推理能力还不错&#xff1b;上线联网功能&#xff0c;类似Kimi那种。 所以呢&#xff0c;用它来读文献就挺舒服的了。例如…

游戏引擎中LOD渲染技术

一.LOD(Level Of Detail) 为了降低GPU渲染压力,根据摄像机距离模型距离将面数较高的模型替换为面数较低的模型. LOD LOD0(distance<10) LOD1(distance<20) LOD2(distance<30) 故通常引擎中MetaMesh是由一个或多个LOD模型构成. MetaMesh mesh mesh.lod1 mesh.lod…

高性能分布式缓存Redis-分布式锁与布隆过滤器

一、分布式锁 我们先来看一下本地锁 在并发编程中&#xff0c;我们通过锁&#xff0c;来避免由于竞争而造成的数据不一致问题。通常&#xff0c;我们以 synchronized 、Lock 来使用它&#xff08;单机情况&#xff09; 来看这段代码 Autowired RedisTemplate<String,Str…

在启动 Spring Boot 项目时,报找不到 slf4j 的错误

而且 tomcat 的启动信息不知道为什么输出出来了 问 AI 得到的解决方案&#xff1a; 将 pom.xml 中的如下配置替换成这样&#xff0c;排除这个插件 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring - boot - starter - …

C/C++ YUV 文件叠加自定义符号

一、前言 需要在图片文件上叠加文字&#xff0c;但是要在4M内存开发板上实现&#xff0c;实际内存不足1M&#xff0c;怎么实现&#xff1f;这个问题在网上查找的解决方案都需要使用第三方库文件&#xff0c;下载文字图像库&#xff0c;但是此开发板不能承受住这么大的内存&…

Android Studio 学习——整体框架和概念

一、创建新项目 选择File-->New-->New Project 这里可以随便选&#xff0c;我一般选择Empty Activity&#xff0c;不同的选择&#xff0c;只是界面不同而已。然后静静的等待安装就可以了 二、框架结构 1&#xff09;manifests manifests文件是一个XML文件&#xff0c;…

「JVM详解」

JVM JVM概述 基本介绍 JVM&#xff1a;全称 Java Virtual Machine&#xff0c;即 Java 虚拟机&#xff0c;一种规范&#xff0c;本身是一个虚拟计算机&#xff0c;直接和操作系统进行交互&#xff0c;与硬件不直接交互&#xff0c;而操作系统可以帮我们完成和硬件进行交互的…

Serverless架构在实时数据处理中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Serverless架构在实时数据处理中的应用 Serverless架构在实时数据处理中的应用 Serverless架构在实时数据处理中的应用 引言 Ser…