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

JavaScript进阶-高阶技巧

文章目录

  • 高阶技巧
    • 深浅拷贝
      • 浅拷贝
      • 深拷贝
    • 异常处理
      • throw抛异常
      • try/caych捕获异常
      • debugger
    • 处理this
      • this指向
      • 改变this
    • 性能优化
      • 防抖
      • 节流


高阶技巧

深浅拷贝

只针对引用类型

浅拷贝

拷贝对象后,里面的属性值是简单数据类型直接拷贝值,如果属性值是引用数据类型则拷贝的是地址
常见语法:
1.拷贝对象:Object.assgin(新变量,被拷贝对象)const 变量名 = {...对象}
2.拷贝数组:Array.prototype.concat()[...arr]
注意:如果是简单数据类型拷贝值,引用数据类型拷贝的是地址(如果是单层对象没有问题,如果是多层对象就有问题)

深拷贝

拷贝的是对象,不是地址
常见方法:

  • 通过递归实现深拷贝
    函数递归:如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
    由于递归容易发生“栈溢出”错误。所以必须要加退出条件return
const obj = {uname:'pink',age:18,hobby:['乒乓球','足球'],family:{baby:'xiaop'}
}
const o = {}
// 拷贝函数
// 深拷贝,拷贝的新对象不会影响旧对象,遇到数组和对象就再次调用递归函数,先数组再对象
function deepCopy(newObj,oldObj) {for(let k in oldObj) {// 一定先写数组,在写对象,因为万物皆对象// 处理数组的问题if (oldObj[k] instanceof Array) {newObj[k] = []// 函数递归deeepCopy(newObj[k],oldObj[k])} // 处理对象的问题else if (oldObj[k] instanceof Object) {newObj[k] = {}deepCopy(newObj[k],oldObj[k])} else {// k属性名,oldObj[k]属性值// newObj[k] === o.unamenewObj[k] = oldObj[k]}}
}
deepCopy(o,obj)// 函数调用两个参数
o.age = 20
console.log(o)
o.hobby[0] = '篮球'
o.family.baby = 'oldp'
console.log(obj)
  • lodash/cloneDeep
    JavaScript库lodash里面cloneDeep内部实现了深拷贝
    语法:const deep = _.cloneDeep(object)
<!-- 先引用 -->
<script src="./lodash.min.js"></script>
<script>const obj = {uname:'pink',age:18,hobby:['乒乓球','足球'],family:{baby:'xiaop'}}const o = _.cloneDeep(obj)o.family.baby = 'oldp'console.log(obj)
</script>
  • 通过JSON.stringfy()实现
const obj = {uname:'pink',age:18,hobby:['乒乓球','足球'],family:{baby:'xiaop'}
}
// JSON.stringify() 把对象转换为JSON字符串
// JSON.parse() 把JSON字符串转换为对象
const o = JSON.parse(JSON.stringify(obj))
o.family.baby = 'oldp'
console.log(obj)

异常处理

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

throw抛异常

1.throw抛出异常信息,程序也会终止执行
2.throw后面跟的是错误提示信息
3.Error对象配合throw使用,能够设置更详细的错误信息

function fn(x,y) {if (!x || !y) {// throw '没有参数传递进来'throw new Error('没有参数传递进来')}return x + y
}

try/caych捕获异常

通过try/catch捕获错误信息(浏览器提供的错误信息)
1.try…catch用于捕获错误信息
2.将预估可能发生了错误的代码写在try代码段中
3.如果try代码段中出现错误后,会执行catch代码段,并截获到错误信息
4.finally不管是否错误,都会执行

function fn() {try {// 可能发生错误的代码要写到tryconst p = document.querySelector('.p')p.style.color = 'red'  } catch (err) {// 拦截错误,提示浏览器提供的错误信息,但是不中断程序的执行console.log(err.message)// 需要return中断程序,可以用throw代替throw new Error('错误')} finally {// 不管你程序对不对,一定会执行的代码alert('弹出对话框')}
}

debugger

在代码中需要调试的地方写debugger,打开控制台后自动来到debugger的位置,类似于断点
在这里插入图片描述

处理this

this指向

  • 普通函数
    普通函数的调用方式决定了this的值,即谁调用就指向谁
    普通函数没有明确调用者时this值为window,严格模式下没有调用者时this的值为undefined
  • 箭头函数
    箭头函数中的this与普通函数完全不同,也不受调用方式影响,事实上箭头函数中并不存在this
    1.箭头函数会默认帮我们绑定外层this的值,所以在箭头函数中this的值和外层的this是一样的
    2.箭头函数中的this引用的就是最近作用域中的this
    3.向外层作用域中,一层一层查找this,直到有this的定义
    注意:
    1.在开发中使用箭头函数前需要考虑函数中this的值,事件回调函数使用箭头函数时,this为全局变量时,this为全局的window
    因此DOM事件回调函数如果里面需要DOM对象的this,则不推荐使用箭头函数
    2.同样由于箭头函数this的原因,基于原型的面向对象也不推荐采用箭头函数

改变this

  • call()
    使用call()方法调用函数,同时指定被调用函数中的this的值
    语法:fn.call(thisArg,arg1,arg2,...)
    thisArg:在fn函数运行时指定的this值
    arg1,arg2:传递的其他参数
    返回值就是函数的返回值,因为它就是调用函数
  • apply()
    使用apply()方法调用函数,同时指定被调用函数中的this的值
    语法:fn.apply(thisArg,[argsArray])
    thisArg:在fn函数运行时指定的this值
    argsArray:传递的值,必须包含在数组里面
    返回值就是函数的返回值,因为它就是调用函数
    因此apply()主要跟数组有关系,比如使用Math.max()求数组的最大值
const obj = {age:18
}
function fn(x,y) {console.log(this)// {age:18}console.log(x + y)// 3
}
// 调用函数
// 改变this指向
fn.apply(obj,[1,2])
// 3.返回值 就是函数的返回值// 使用场景:求数组最大值
const arr = [1,2,3]
const max = Math.max.apply(Math,arr)
// console.log(Math.max(...arr))
console.log(max)// 3
  • bind()(重点)
    bind()方法不会调用函数,但是能改变函数内部this指向
    语法:fn.bind(thisArg,arg1,arg2...)
    thisArg:在fn函数运行时指定的this的值
    arg1,arg2:传递的其他参数
    返回由指定的this值和初始化参数改造的原拷贝函数(新函数)
    因此当我们只是想改变this指向,并且不想调用这个函数的时候,可以使用bind,比如改变计时器内部的this指向
const obj = {age:18
}
function fn() {console,log(this)
}
// 返回值是个函数,但是这个函数里面的this是更改过的
const fn = fn.bind(obj)
// console.log(fn)
fn()// {age:18}
<body><button>发送</button><script>// 需求,有一个按钮,点击里面就禁用,2秒钟之后开始const btn = document.querySelector('button')btn.addEventListener('click', function() {// 禁用按钮this.display = true//this指向btnsetTimeout(function() {// 在这个普通函数里面,要this由原来的window改为btnthis.disabled = false}.bind(this),2000)//这个this是上面指向btn的this})</script>
</body>

性能优化

防抖

防抖:单位时间内,频繁触发事件,只执行最后一次
使用场景:
1.搜索框搜索输入。只需要用户最后一次输入完,再发送请求
2.手机号、邮箱验证输入检测
在这里插入图片描述
常用方法:

  • lodash提供的防抖来处理
    语法:_.debounce(func,[wait=0],[options=])
    func:要防抖的函数
    [wait=0]:需要延迟的毫秒数
    [options=]:选项对象
  • 手写防抖函数
    核心思路:利用定时器(setTimeout)来实现

例如:

<style>.box {width:500px;height:500px;background-color:#ccc;color:#fff;text-align:center;font-size:100px;}
</style>
<body><div class="box"></div><script src='./lodash.min.js'><script>// 利用防抖实现性能优化// 需求:鼠标在盒子上移动,里面的数字就会变化+1const box = document.querySelector('.box')let i = 1function mouseMove() {box.innerHTML = i++// 如果里面存在大量消耗性能的代码,比如DOM操作、数据处理,可能造成卡顿}// 添加事件// box.addEventListener('mousemove',mouseMove)// 利用lodash库实现防抖 500毫秒之后+1box.addEventListener('mousemove',_.debounce(mouseMove,500))// 手写函数部分// 1.声明定时器变量// 2.每次鼠标移动(事件触发)的时候都要先判断是否有定时器,如果有先清除以前的定时器// 3.如果没有定时器,则开启定时器,存入到定时器变量里面// 4.定时器里面写函数调用function debounce(fn,t) {let timer// return返回一个匿名函数return function() {if(timer) {clearTimeout(timer)}	timer = setTimeout(function() {fn()//加小括号调用fn函数},t)	}}box.addEventListener('mousemove',debounce(mouseMove,500))</script>
</body>

节流

节流:单位时间内,频繁触发事件,只执行一次
使用场景:
高频事件:鼠标移动mousemove、页面尺寸缩放resize、滚动条滚动scroll
在这里插入图片描述
常用方法:

  • lodash提供的节流函数来处理
    语法:_.throttle(func,[wait=0],[options=])
    func:要节流的函数
    [wait=0]:需要节流的毫秒数
    [options=]:选项对象
    [options.leading=true]:指定调用在节流开始前
    [options.leading=false]:指定调用在节流结束后
  • 手写一个节流函数来处理
    核心思路:利用定时器(setTimeout)来实现

例如:

<style>.box {width:500px;height:500px;background-color:#ccc;color:#fff;text-align:center;font-size:100px;}
</style>
<body><div class="box"></div><script src='./lodash.min.js'><script>// 利用节流实现性能优化// 需求:鼠标在盒子上移动,里面的数字就会变化+1const box = document.querySelector('.box')let i = 1function mouseMove() {box.innerHTML = i++// 如果里面存在大量消耗性能的代码,比如DOM操作、数据处理,可能造成卡顿}// 添加事件// box.addEventListener('mousemove',mouseMove)// 利用lodash库实现节流 500毫秒之后+1box.addEventListener('mousemove',_.throttle(mouseMove,500))// 手写函数部分// 1.声明一个定时器变量// 2.当鼠标每次滑动都先判断是否有定时器,如果有定时器则不开启新定时器// 3.如果没有定时器则开启定时器,记得存到变量里面// 3.1定时器里面调用执行的函数// 3.2定时器里面要把定时器清空function throttle(fn,t) {let timer = nullreturn function() {if(!timer) {timer = setTime(function() {fn()// 清空定时器// 在setTimeout中是无法删除定时器的,因为定时器还在运作,故不使用clearTimeront(timer)timer = null},t)}}}box.addEventListener('mousemove',throttle(mouseMove,500))</script>
</body>

相关文章:

JavaScript进阶-高阶技巧

文章目录 高阶技巧深浅拷贝浅拷贝深拷贝 异常处理throw抛异常try/caych捕获异常debugger 处理thisthis指向改变this 性能优化防抖节流 高阶技巧 深浅拷贝 只针对引用类型 浅拷贝 拷贝对象后&#xff0c;里面的属性值是简单数据类型直接拷贝值&#xff0c;如果属性值是引用数…...

C语言中“#“和“##“的用法

1. 前言 # &#xff1a;把宏参数变为一个字符串, ##&#xff1a;把两个宏参数贴合在一起. 2. 一般用法 #include<stdio.h> #define toString(str) #str //转字符串 #define conStr(a,b) (a##b)//连接 int main() { printf(toString(12345)): //输出字符串&q…...

Linux命令-clock命令(用于调整 RTC 时间)

说明 clock命令用于调整 RTC 时间。 RTC 是电脑内建的硬件时间&#xff0c;执行这项指令可以显示现在时刻&#xff0c;调整硬件时钟的时间&#xff0c;将系统时间设成与硬件时钟之时间一致&#xff0c;或是把系统时间回存到硬件时钟。 语法 clock [--adjust][--debug][--dir…...

编程笔记 Golang基础 045 math包

编程笔记 Golang基础 045 math包 一、math包主要功能常量&#xff1a;函数&#xff1a;数值运算&#xff1a;三角函数&#xff1a;对数函数&#xff1a;随机数相关&#xff1a; 二、示例代码一三、示例代码二小结 Go 语言的标准库 math 提供了一系列基础数学函数和常量&#xf…...

[Java 探索者之路] 一个大厂都在用的分布式任务调度平台

分布式任务调度平台是一种能够在分布式计算环境中调度和管理任务的系统&#xff0c;在此环境下&#xff0c;各个任务可以在独立的节点上运行。它有助于提升资源利用率&#xff0c;增强系统扩展性以及提高系统对错误的容忍度。 文章目录 1. 分布式任务调度平台1. 基本概念1.1 任…...

基于JAVA springboot+mybatis智慧生活分享平台设计和实现

基于JAVA springbootmybatis智慧生活分享平台设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末…...

详细了解C++中的namespace命名空间

键盘敲烂&#xff0c;月薪过万&#xff0c;同学们&#xff0c;加油呀&#xff01; 目录 键盘敲烂&#xff0c;月薪过万&#xff0c;同学们&#xff0c;加油呀&#xff01; 一、命名空间的理解 二、&#xff1a;&#xff1a;作用域运算符 三、命名空间&#xff08;namespace&…...

#WEB前端(HTML属性)

1.实验&#xff1a;a,img 2.IDE&#xff1a;VSCODE 3.记录&#xff1a; a: href插入超链接 默认情况下在本窗口打开链接, target可以设置打开的窗口,parent在父窗口打开&#xff0c;blank新开串口打开,top在顶层串口打开,self为默认在本窗口打开 img: 插入图片 可以插…...

LeetCode---【和的操作】

目录 两数之和我的答案在b站up那里学到的【然后自己复写】 和为 K 的子数组在b站up那里学到的【然后自己复写】 三数之和在b站up那里学到的【然后自己复写】 两数相加【链表】我的半路答案&#xff1a;没有看到是链表在b站up那里学到的【复写失败后整理】 两数之和 我的答案 …...

Docker容器与虚拟化技术:OpenEuler 使用 docker-compose 部署 LNMP

目录 一、实验 1.环境 2.OpenEuler 部署 docker-compose 3.docker-compose 部署 LNMP 二、问题 1.ntpdate未找到命令 2.timedatectl 如何设置时区与时间同步 3.php网页显示时区不对 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统架构版本IP备注Lin…...

13-微服务初探-自研微服务框架

微服务初探 1. 架构变迁之路 1.1 单体架构 互联网早期&#xff0c;一般的网站应用流量较小&#xff0c;只需要一个应用&#xff0c;将所有的功能代码都部署在一起就可以&#xff0c;这样可以减少开发&#xff0c;部署和维护的成本。 比如说一个电商系统&#xff0c;里面包含…...

LeetCode——二叉树(Java)

二叉树 简介[简单] 144. 二叉树的前序遍历、94. 二叉树的中序遍历、145. 二叉树的后序遍历二叉树层序遍历[中等] 102. 二叉树的层序遍历[中等] 107. 二叉树的层序遍历 II[中等] 199. 二叉树的右视图[简单] 637. 二叉树的层平均值[中等] 429. N 叉树的层序遍历[中等] 515. 在每个…...

LDR6328芯片:智能家居时代的小家电充电革新者

在当今的智能家居时代&#xff0c;小家电的供电方式正变得越来越智能化和高效化。 利用PD&#xff08;Power Delivery&#xff09;芯片进行诱骗取电&#xff0c;为后端小家电提供稳定电压的技术&#xff0c;正逐渐成为行业的新宠。在这一领域&#xff0c;LDR6328芯片以其出色的…...

用node写后端环境运行时报错Port 3000 is already in use

解决方法:关闭之前运行的3000端口,操作如下 1.WindowR输入cmd确定,打开命令面板 2.查看本机端口详情 netstat -ano|findstr "3000" 3.清除3000端口 taskkill -pid 41640 -f 最后再重新npm start即可,这里要看你自己项目中package.joson的启动命令是什…...

Git 如何上传本地的所有分支

Git 如何上传本地的所有分支 比如一个本地 git 仓库里定义了两个远程分支&#xff0c;一个名为 origin&#xff0c; 一个名为 web 现在本地有一些分支是 web 远程仓库没有的分支&#xff0c;如何将本地所有分支都推送到 web 这个远程仓库上呢 git push web --all...

【airtest】自动化入门教程(一)AirtestIDE

目录 一、下载与安装 1、下载 2、安装 3、打开软件 二、web自动化配置 1、配置chrome浏览器 2、窗口勾选selenium window 三、新建项目&#xff08;web&#xff09; 1、新建一个Airtest项目 2、初始化代码 3、打开一个网页 四、恢复默认布局 五、新建项目&#xf…...

ChatGPT支持下的PyTorch机器学习与深度学习技术应用

近年来&#xff0c;随着AlphaGo、无人驾驶汽车、医学影像智慧辅助诊疗、ImageNet竞赛等热点事件的发生&#xff0c;人工智能迎来了新一轮的发展浪潮。尤其是深度学习技术&#xff0c;在许多行业都取得了颠覆性的成果。另外&#xff0c;近年来&#xff0c;Pytorch深度学习框架受…...

Springboot+vue的医药管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的医药管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层…...

C语言:预处理

C语言&#xff1a;预处理 预定义符号#define定义常量定义宏宏与函数对比 #操作符##操作符条件编译头文件包含库文件包含本地文件包含嵌套文件包含 预定义符号 C语⾔设置了⼀些预定义符号&#xff0c;可以直接使⽤&#xff0c;预定义符号也是在预处理期间处理的。 __FILE__ //…...

计算机网络:路由协议

路由协议简介 路由协议是计算机网络中不可或缺的一部分&#xff0c;它们负责确定数据包从源地址到目的地址的最佳路径。想象一下&#xff0c;如果你是一个数据包&#xff0c;路由协议就像是地图或导航工具&#xff0c;指导你如何到达目的地。 目录 路由协议简介 工作原理简化…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...

麒麟系统使用-进行.NET开发

文章目录 前言一、搭建dotnet环境1.获取相关资源2.配置dotnet 二、使用dotnet三、其他说明总结 前言 麒麟系统的内核是基于linux的&#xff0c;如果需要进行.NET开发&#xff0c;则需要安装特定的应用。由于NET Framework 是仅适用于 Windows 版本的 .NET&#xff0c;所以要进…...

2.2.2 ASPICE的需求分析

ASPICE的需求分析是汽车软件开发过程中至关重要的一环&#xff0c;它涉及到对需求进行详细分析、验证和确认&#xff0c;以确保软件产品能够满足客户和用户的需求。在ASPICE中&#xff0c;需求分析的关键步骤包括&#xff1a; 需求细化&#xff1a;将从需求收集阶段获得的高层需…...