【JS学习】15. JS进阶-深浅拷贝等

JavaScript 进阶 - 第4天

深浅拷贝

浅拷贝

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

浅拷贝:拷贝的是地址

常见方法:

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

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

深拷贝

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

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

常见方法:

  1. 通过递归实现深拷贝
  2. lodash/cloneDeep
  3. 通过JSON.stringify()实现
递归实现深拷贝

函数递归:

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

  • 简单理解:函数内部自己调用自己, 这个函数就是递归函数
  • 递归函数的作用和循环效果类似
  • 由于递归很容易发生“栈溢出”错误(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>
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>
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/news/885965.shtml

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

相关文章

WebSocket和HTTP协议的性能比较与选择

WebSocket和HTTP协议的性能比较与选择 引言&#xff1a; 在web应用开发中&#xff0c;无论是实时聊天应用、多人在线游戏还是实时数据传输&#xff0c;网络连接的稳定性和传输效率都是关键要素之一。目前&#xff0c;WebSocket和HTTP是两种常用的网络传输协议&#xff0c;它们…

Prompt Engineering 提示工程

一、什么是提示工程&#xff08;Prompt Engineering&#xff09; Prompt 就是发给大模型的指令&#xff0c;比如讲个笑话、用 Python 编个贪吃蛇游戏等&#xff1b;大模型只接受一种输入&#xff0c;那就是 prompt。本质上&#xff0c;所有大模型相关的工程工作&#xff0c;都是…

智慧水利综合解决方案

1. 引言 智慧水利综合解决方案集成了先进的信息技术与水利专业知识&#xff0c;旨在提升水资源管理与防洪减灾能力&#xff0c;实现水利管理的智能化与高效化。 2. 数字孪生技术 方案利用数字孪生技术构建流域数字模型&#xff0c;通过高精度模拟仿真&#xff0c;为水资源调度…

网络安全工程师要考什么证书

在当今数字化时代&#xff0c;网络安全已成为各行各业不可忽视的重要领域。随着网络攻击手段的不断升级&#xff0c;企业对网络安全人才的需求也日益迫切。网络安全工程师作为这一领域的专业人才&#xff0c;承担着保护企业信息安全、防范网络威胁的重要职责。那么&#xff0c;…

Python在数据科学中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Python在数据科学中的应用 Python在数据科学中的应用 Python在数据科学中的应用 引言 Python 概述 定义与特点 发展历程 Python…

机器学习:决策树——ID3算法、C4.5算法、CART算法

决策树是一种常用于分类和回归问题的机器学习模型。它通过一系列的“决策”来对数据进行分类或预测。在决策树中&#xff0c;每个内部节点表示一个特征的测试&#xff0c;每个分支代表特征测试的结果&#xff0c;而每个叶节点则表示分类结果或回归值。 决策树工作原理 根节点&…

大数据-221 离线数仓 - 数仓 数据集市 建模方法 数仓分层 ODS DW ADS

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

aws中AcmClient.describeCertificate返回值中没有ResourceRecord

我有一个需求&#xff0c;就是让用户自己把自己的域名绑定我们的提供的AWS服务器。 AWS需要验证证书 上一篇文章中我用php的AcmClient中的requestCertificate方法申请到了证书。 $acmClient new AcmClient([region > us-east-1,version > 2015-12-08,credentials>[/…

C++20 概念与约束(2)—— 初识概念与约束

《C20 概念与约束&#xff08;1&#xff09;—— SFINAE》 ●《C20 概念与约束&#xff08;2&#xff09;—— 初识概念与约束》 《C20 概念与约束&#xff08;3&#xff09;—— 约束的进阶用法》 1、概念 C20 中引入新的编译期关键字 concept 用于创建概念。个人认为将其…

拦截器实现http请求访问本地图片

本文来记录下拦截器实现http请求访问本地图片 文章目录 概述代码实现本文小结 概述 如下图&#xff0c;本机(服务器)存储的图片想要在浏览器上通过Url地址访问&#xff1a; 浏览器直接访问 代码实现 烂机器实现文件真实地址和物理地址之间的映射 Slf4j Configuration public cl…

Python技巧:查询模块的版本号的方法

1,pycharm里面的 Python interpreter 或者 Python package 2&#xff0c;通过 __version_info__ import matplotlib print(matplotlib.__version_info__) 3&#xff0c;查看目录里面的 _version.py 文件

计算机网络——HTTP篇

基础篇 IOS七层网络模型 TCP/IP四层模型&#xff1f; 应⽤层&#xff1a;位于传输层之上&#xff0c;主要提供两个终端设备上的应⽤程序之间的通信&#xff0c;它定义了信息交换的格式&#xff0c;消息会交给下⼀层传输层来传输。 传输层的主要任务就是负责向两台设备进程之间…

Unity插件NodeCanvas之行为树的详细教程

文章目录 前言叶节点 Leafs1、行为 Action2、判断 Condition控制组件 Composites1、顺序执行器 Sequencer2、选择执行器 Selector3、概率选择执行器 Probability Selector4、权重选择执行器 Priority Selector5、平行执行器 Parallel6、轮流选择器 Flip Selector7、完整执行器 …

Qt 使用QTreeView显示并动态的增删改查JSON文件数据

文章目录 效果图概述部分代码总结 效果图 概述 本案例在此开源项目QJsonModel的基础上实现&#xff0c;动态的生成并操作JSON数据&#xff0c;QJsonModel是一个基于QAbstractItemModel的JSON数据模型&#xff0c;它提供了一种简单的方式来将JSON数据可视化&#xff0c;功能简单…

计算机专业可以报考公务员吗?都有哪些职位?

C哥专业提供——计软考研院校选择分析专业课备考指南规划 计算机专业是历年来考公的热门专业&#xff0c;岗位较多&#xff0c;且研究生进入体制内直接是副科级待遇&#xff0c;铁饭碗还是很香的&#xff01; 25国考计算机专业可以选择的岗位 招聘人数&#xff1a;学硕>专硕…

视频智能分析平台LiteAIServer算法定制未戴安全帽检测技术:智能安防领域的新篇章

在当今这个科技日新月异的时代&#xff0c;人工智能&#xff08;AI&#xff09;和计算机视觉技术的飞速发展正在以前所未有的速度改变我们的生活、工作乃至整个社会的面貌。在建筑行业中&#xff0c;安全问题一直是重中之重&#xff0c;而工人未戴安全帽的问题更是工地安全管理…

C++ 优先算法 —— 四数之和(双指针)

目录 题目&#xff1a;四数之和 1. 题目解析 2. 算法原理 Ⅰ. 暴力枚举 Ⅱ. 双指针算法 不漏的处理&#xff1a; 去重处理&#xff1a; 3. 代码实现 Ⅰ. 暴力枚举 Ⅱ. 双指针算法 题目&#xff1a;四数之和 1. 题目解析 题目截图&#xff1a; 这道题与三数之和&am…

思考:linux Vi Vim 编辑器的简明原理,与快速用法之《 7 字真言 》@ “鱼爱返 说 温泉啊“ (**)

Linux vi/vim | 菜鸟教程 https://zhuanlan.zhihu.com/p/602675406 Linux Vim编辑器的基本使用_vim文本编辑器-CSDN博客 这里提出使用 vi / vim 进行简单的编辑操作的原因&#xff0c;主要是在容器镜像中&#xff0c;普遍都是使用这个。 在 linux 服务器应用场景&#x…

C# 通俗易懂的介绍基础知识(七)——栈Stack(从日常生活开始讲解)

目录 一、前言 二、栈是排列方式 三、栈的单词 四、程序中的栈 五、栈的方法 1.声明并初始化栈 2.往栈里放东西&#xff08;学名&#xff1a;入栈&#xff09; 3.从栈往外拿东西 &#xff08;学名&#xff1a;出栈&#xff09; 4.清空栈 5.遍历 Stack 6.获取Stack的长…

React Query在现代前端开发中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 React Query在现代前端开发中的应用 React Query在现代前端开发中的应用 React Query在现代前端开发中的应用 引言 React Query …