【JS进阶】第四天

JavaScript 进阶 - 第 4 天

深浅拷贝

浅拷贝

首先浅拷贝和深拷贝只针对引用类型,因为简单类型直接拷贝值了

浅拷贝:拷贝的是地址,只拷贝一层
在这里插入图片描述
常见方法:

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

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

里面的属性值是简单数据类型就直接拷贝值;
如果属性值是引用数据类型则拷贝的是地址;

深拷贝

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

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

常见方法:

  1. 通过递归实现深拷贝
  2. js 的库: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) {debugger;for (let k in oldObj) {// k 是属性名,oldObj[k]是属性值// 处理数组的问题  一定先写数组 在写 对象 不能颠倒,因为一切皆对象,要是把对象写前面,Array就永远没有机会了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 = 20;o.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>
    const arr = [1, 2];// 处理数组的问题  一定先写数组 在写 对象 不能颠倒,因为一切皆对象,要是把对象写前面,Array就永远没有机会了console.log(arr instanceof Array);  // trueconsole.log(arr instanceof Object);  // true
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 序列化

JSON.stringify(obj) 把对象转换成JSON字符串
JSON.parse(obj) 把字符串转换成对象

<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 = sayHi;uesr.sayHello = sayHello;// 函数调用方式,决定了 this 的值user.sayHi();  // useruser.sayHello();  // user
</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); // 箭头函数本身没有this,所以往上找,user是对象,也没有this,所以继续向上找,所以最后是window},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 事件回调函数不推荐使用箭头函数,如下代码所示:

  <body><button id="pu">click普通函数</button><button id="jian">click箭头函数</button></body><script>document.querySelector("#pu").addEventListener("click", function () {console.log("click普通函数", this);  // button});document.querySelector("#jian").addEventListener("click", () => {console.log("箭头函数", this);  // window});</script>
<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 的原因,基于原型的面向对象也不推荐采用箭头函数,如下代码所示:
构造函数和原型的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 (了解即可

作用:调用函数 + 改变this指向
在这里插入图片描述

使用 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 方法的其余参数会依次自动传入函数做为函数的参数
  4. 返回值就是函数的返回值
apply

在这里插入图片描述

使用 apply 方法调用函数,同时指定函数中 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 个参数为数组,数组的单元值依次自动传入函数做为函数的参数
  4. 返回值就是函数的返回值
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. 参数形式:call 和bind 是直接穿参数 ,apply是数组的形式传递参数
  2. 是否会调用函数:call 和apply 会调用;但是bind不会调用
  3. 返回值:bind返回由指定的this和初始化参数改造的新函数(原函数拷贝); 而call和bind的返回值是函数的返回值
    在这里插入图片描述

防抖节流

防抖(debounce)

概念

单位时间内,频繁出发事件,只执行一次,且只执行最后一次。
只要被打断就重新来。
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

使用场景:
  1. 搜索框搜索输入,只需用户最后一次输入完,再发送请求
  2. 手机号、邮箱验证输入
代码实战

在这里插入图片描述

节流(throttle)

概念

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

使用场景

在这里插入图片描述

代码实战

在这里插入图片描述
在这里插入图片描述

总结

在这里插入图片描述

【节流】综合案例——跳转到历史播放时刻

在这里插入图片描述onloaddata也可以理解成 打开页面触发事件

但是ontimeupdate的出发频次太高了,需要节流,可以设置1秒钟触发一次

在这里插入图片描述
黑马讲解视频

在这里插入图片描述

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

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

相关文章

Linux_ubuntu使用常见问题解决

文章目录 1.安装好了搜狗输入法却只能输出英文&#xff1a; 1.安装好了搜狗输入法却只能输出英文&#xff1a; 1.浏览器搜索搜狗输入法&#xff0c;下载好安装包 终端输入下列命令安装&#xff0c;找不到文件可以cd到该安装包的目录文件下&#xff1a; sudo dpkg -i sogoupin…

自定义vue-cli 实现预设模板项目

模板结构 主要包括四个部分&#xff1a; preset.jsonprompts.jsgenerator/index.jstemplate/ 项目最终结构 preset.json preset.json 中是一个包含创建新项目所需预定义选项和插件的 JSON 对象&#xff0c;让用户无需在命令提示中选择它们&#xff0c;简称预设&#xff1b;…

从 0 搭建公司Jenkins服务 Centos7

从 0 搭建公司Jenkins服务 Centos7 安装 (运维人员) 安装环境 配置DNS安装JDK17安装Jenkins安装Docker安装GIT安装Ansible启动Jenkins安装插件配置凭据配置共享库配置 (开发经理)使用 (开发、测试人员) 安装 (运维人员) 安装环境 配置DNS 新安装系统的服务器无法解析域名&a…

云计算重要概念之:虚拟机、网卡、交换机、路由器、防火墙

一、虚拟机 (Virtual Machine, VM) 1.主流的虚拟化软件&#xff1a; 虚拟化软件通过在单个物理硬件上创建和管理多个虚拟环境&#xff08;虚拟机&#xff09;&#xff0c;实现资源的高效利用、灵活部署、隔离安全以及便捷管理&#xff0c;是构建云计算和现代化数据中心的核心…

B端:弹窗的场景、类型、 选择策略串讲,让你的设计有理有据。

B端产品在什么情况下使用弹窗&#xff0c;弹窗又分为哪些类型&#xff0c;该如何选择合理的弹窗形式&#xff0c;很多小伙伴都是跟着感觉走&#xff0c;本文告诉你依据。 一、弹窗及其场景 在B端系统中&#xff0c;"B端"通常指的是面向企业&#xff08;Business&am…

VMware Workstation部署最新版OpenWrt 23.05.3

正文共&#xff1a;1456 字 51 图&#xff0c;预估阅读时间&#xff1a;2 分钟 我们之前介绍了如何在VMware Workstation上安装OpenWrt&#xff08;软路由是啥&#xff1f;OpenWrt又是啥&#xff1f;长啥样&#xff1f;在VMware装一个瞅瞅&#xff09;&#xff0c;也介绍了如何…

十分钟学懂Java并发

并发简介 我们学到的基本上都是有关顺序编程的知识&#xff0c;即程序中所有事物在任意时刻都只能执行一个步骤。 编程问题中相当大的一部分都可以通过使用顺序编程来解决。然而&#xff0c;对于某些问题&#xff0c;如果能够并发地执行程序中的多个部分&#xff0c;则会变得非…

lua学习笔记19(面相对象学习的一点总结)

print("*****************************面相对象总结*******************************") object{} --实例化方法 function object:new()local obj{}self.__indexselfsetmetatable(obj,self)return obj end-------------------------如何new一个对象 function object:…

1688商品详情接口技术深探:解锁电商数据新纪元,实现业务自动化飞跃

1688商品详情接口技术解析 一、引言 随着电子商务的快速发展&#xff0c;越来越多的企业开始关注如何利用API接口获取商品详情信息&#xff0c;以实现数据的自动化处理和业务的快速拓展。1688作为国内知名的B2B电商平台&#xff0c;其商品详情接口成为了众多企业关注的焦点。…

三小时使用鸿蒙OS模仿羊了个羊,附源码

学习鸿蒙arkTS语言&#xff0c;决定直接通过实践的方式上手&#xff0c;而不是一点点进行观看视频再来实现。 结合羊了个羊的开发思路&#xff0c;准备好相应的卡片素材后进行开发。遇到了需要arkTS进行解决的问题&#xff0c;再去查看相应的文档。 首先需要准备卡片对应的图片…

什么是JAVA面向对象

一&#xff0c;什么是面向对象&#xff1a; 我们以前的项目都是面向过程的&#xff0c;一个完整的项目所有的代码都写在一个类里 这就叫面向过程。 面向对象&#xff0c;是指在写大型项目时&#xff0c;多人分工合作&#xff0c;为了代码看上去简洁美观&#xff0c;会将不同的…

2023-2024年科技行业主要变化趋势梳理与总结

一、主要大额并购案例并购原因 &#xff08;一&#xff09;产品线补充与业务市场拓展&#xff08;如VMware、Activision Blizzard并购案&#xff09; &#xff08;二&#xff09;技术整合&#xff08;如Spunk并购案&#xff09;、 &#xff08;三&#xff09;优化运营以期溢…

MFC:手写一个模态对话框程序

我们知道&#xff0c;在MFC中&#xff0c;要生成一个模态对话框程序&#xff0c;只要按着VS的提示&#xff0c;拖拖拽拽就能生成一个这样的程序&#xff0c;效率非常高。这里&#xff0c;我们反其道而行之&#xff0c;自己写一个这样的程序&#xff0c;这个程序与自动生成的程序…

机器学习和深度学习 --李宏毅(笔记与个人理解)Day 18

Day 18 Spatial Transformer Layer 因为单纯的cNN无法做到scaling&#xff08;放大&#xff09;and rotation&#xff08;转&#xff09;&#xff0c;所以我们引入&#xff1b; 实战中也许我们可以做到 是因为 我们的training data 中包含了对data 的augmentation&#xff1b; …

设计模式——外观(门面)模式10

外观模式&#xff1a;能为系统框架或其他复杂业务流程封装提供一个简单的接口。 例如抽奖过程中 设计模式&#xff0c;一定要敲代码理解 调用1&#xff08;抽奖系统&#xff09; /*** author ggbond* date 2024年04月08日 10:34*/ public class Lottery {public String getId…

帝国cms仿《鳄鱼下载站》网站源码

仿《鳄鱼下载站》网站源码手机安卓软件网站模版 PHP网站源码 帝国cms内核 采用帝国cms7.5 环境PHPmysql 恢复数据库后如何修改密码: 双击表&#xff0c;进入对应的详细数据表&#xff0c;然后找到&#xff1a;www_96kaifa_com_enewsuser这个表&#xff0c;双击打开修改&…

python画神经网络图

代码1(画神经网络连接图&#xff09; from math import cos, sin, atan import matplotlib.pyplot as plt # 注意这里并没有用到这个networkx这个库&#xff0c;完全是根据matploblib这个库来画的。 class Neuron():def __init__(self, x, y,radius,nameNone):self.x xself.y …

Substance 3D2024版 下载地址及安装教程

Substance 3D是Adobe公司推出的一套全面的3D设计和创作工具集合&#xff0c;用于创建高质量的3D资产、纹理和材质。 Substance 3D包括多个功能强大的软件和服务&#xff0c;如Substance 3D Painter、Substance 3D Designer和Substance 3D Sampler等。这些工具提供了广泛的功能…

智过网:注册安全工程师注册有效期与周期解析

在职业领域&#xff0c;各种专业资格认证不仅是对从业者专业能力的认可&#xff0c;也是保障行业安全、规范发展的重要手段。其中&#xff0c;注册安全工程师证书在安全生产领域具有举足轻重的地位。那么&#xff0c;注册安全工程师的注册有效期是多久呢&#xff1f;又是几年一…

数据可视化的3D问题

三维对象非常流行&#xff0c;但在大多数情况下会对解释图形的准确性和速度产生负面影响。 以下是对涉及 3d 的主要图形类型的回顾&#xff0c;并讨论了它们是否被认为是不好的做法。 1、3D 条形图&#xff1a;不要 这是一个 3d 条形图。 你可能很熟悉这种图形&#xff0c;因为…