镇江网站设计多少钱/成都seo培训班
JavaScript 进阶
文章目录
- JavaScript 进阶
- 深浅拷贝
- 浅拷贝
- 深拷贝
- 递归实现深拷贝
- js库lodash里面cloneDeep内部实现了深拷贝
- JSON序列化
- 异常处理
- throw
- try ... catch
- debugger
- 处理this
- 普通函数
- 箭头函数
- 改变this指向
- call
- apply
- bind
- 防抖节流
深浅拷贝
浅拷贝
首先浅拷贝和深拷贝只针对引用类型
浅拷贝:拷贝的是地址
常见方法:
- 拷贝对象:Object.assgin() / 展开运算符 {…obj} 拷贝对象
- 拷贝数组:Array.prototype.concat() 或者 […arr]
如果是简单数据类型拷贝值,引用数据类型拷贝的是地址 (简单理解: 如果是单层对象,没问题,如果有多层就有问题)
深拷贝
首先浅拷贝和深拷贝只针对引用类型
深拷贝:拷贝的是对象,不是地址
常见方法:
- 通过递归实现深拷贝
- lodash/cloneDeep
- 通过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
异常处理是指预估代码执行过程中可能发生的错误,然后最大程度的避免错误的发生导致整个程序无法继续运行
总结:
- throw 抛出异常信息,程序也会终止执行
- throw 后面跟的是错误提示信息
- Error 对象配合 throw 使用,能够设置更详细的错误信息
<script>function counter(x, y) {if(!x || !y) {// throw '参数不能为空!';throw new Error('参数不能为空!')}return x + y}counter()
</script>
总结:
throw
抛出异常信息,程序也会终止执行throw
后面跟的是错误提示信息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>
总结:
try...catch
用于捕获错误信息- 将预估可能发生错误的代码写在
try
代码段中 - 如果
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>
总结:
call
方法能够在调用函数的同时指定this
的值- 使用
call
方法调用函数时,第1个参数为this
指定的值 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>
总结:
apply
方法能够在调用函数的同时指定this
的值- 使用
apply
方法调用函数时,第1个参数为this
指定的值 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
的值。
防抖节流
- 防抖(debounce)
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间 - 节流(throttle)
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数
相关文章:

JavaScript Es6_4笔记
JavaScript 进阶 文章目录 JavaScript 进阶深浅拷贝浅拷贝深拷贝递归实现深拷贝js库lodash里面cloneDeep内部实现了深拷贝JSON序列化 异常处理throwtry ... catchdebugger 处理this普通函数箭头函数改变this指向callapplybind 防抖节流 深浅拷贝 浅拷贝 首先浅拷贝和深拷贝只…...

Python“牵手”易贝(Ebay)商品列表数据,关键词搜索ebayAPI接口数据,ebayAPI接口申请指南
Ebay平台API接口是为开发电商类应用程序而设计的一套完整的、跨浏览器、跨平台的接口规范, EbayAPI接口是指通过编程的方式,让开发者能够通过HTTP协议直接访问Ebay平台的数据,包括商品信息、店铺信息、物流信息等,从而实现Ebay平…...

C语言:选择+编程(每日一练Day8)
目录 选择题: 题一: 题二: 题三: 题四: 题五: 编程题: 题一:字符个数统计 思路一: 题二:多数元素 思路一: 本人实力有限可能对一些…...

使用 uniapp 适用于wx小程序 - 实现移动端头部的封装和调用
图例:红框区域,使其标题区与胶囊对齐 一、组件 navigation.vue <template><view class"nav_name"><view class"nav-title" :style"{color : props.color, padding-top : toprpx,background : props.bgColor,he…...

ARM Linux 系统稳定性分析入门及渐进 13 -- gdb 反汇编 disassemble 命令详细介绍及举例】
文章目录 1.1 gdb 调试回顾1.1.1 gdb list 命令介绍 1.2 反汇编命令 dis 介绍1.2.1 如何设置 gdb 汇编代码的格式 1.1 gdb 调试回顾 在GNU调试器(GDB)中,有许多命令可以帮助我们调试应用程序。 gdb: 这是一个强大的Unix下的程序调试工具。以…...

python连接Microsoft SQL Server 数据库
python代码 Author: tkhywang 2810248865qq.com Date: 2023-08-21 11:22:24 LastEditors: tkhywang 2810248865qq.com LastEditTime: 2023-08-21 11:29:30 FilePath: \PythonProject02\Microsoft SQL Server 数据库.py Description: 这是默认设置,请设置customMade, 打开koroFi…...

docker可视化工具
安装Portainer 官方安装说明:https://www.portainer.io/installation/ [rootubuntu1804 ~]#docker pull portainer/portainer[rootubuntu1804 ~]#docker volume create portainer_data portainer_data [rootubuntu1804 ~]#docker run -d -p 8000:8000 -p 9000:90…...

MySQL 用户管理操作
目录 一、用户管理概述 二、用户管理 1、创建用户 2、删除用户 三、账户密码管理 1、root用户修改自己的密码 2、ROOT用户修改其他普通用户密码 3、普通用户修改自己的密码 4、ROOT用户密码忘记解决办法 1)Linux系统 2)windows系统 四、用户权…...

【python办公自动化】PysimpleGUI中的popup弹窗中的按钮设置居中
PysimpleGUI中的popup弹窗中的按钮设置居中 背景问题解决背景 默认的popup弹窗中的OK按钮是在最下面偏左侧一些,有时需要将按钮放置居中 问题解决 首先找到pysimplegui源代码文件中popup的部分 然后定位到19388行,源文件内容如下 关于popup弹窗OK按钮的设置,将pad属性…...

postgresql 同步流复制两个相关参数synchronous_commit 和 synchronous_standby_names
一:synchronous_commit 1.synchronous_commit参数含义 这个参数用来设置事务提交返回客户端之前,一个事务是否需要等待 WAL 记录被写入磁盘。合法的值是{local,remote_write,remote_apply,on,off}。默认设置是on。 2.各可选值含义 2.1 local 当事务…...

运算放大器发展史
在内部集成了一个补偿电容 MPS公司OP07推出后,大受欢迎。各家厂商都推出了自己的 这4款都是可以替换的...

LVS+Keepalived 实验
Keepalived 是什么 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以解决静态路由出现的单点故障问题的一款检查工具 在一个LVS服务集群中通常有主服务器(MASTER)和备份服务器(BACKUP)两种角色的服务器…...

FreeSWITCH 1.10.10 简单图形化界面1 - docker/脚本/ISO镜像安装
FreeSWITCH 1.10.10 简单图形化界面1 - docker/脚本/ISO镜像安装 0. 界面预览1. Docker安装1.1 下载docker镜像1.2 启动docker镜像1.3 登录 2. 脚本安装2.1 下载2.2 安装2.3 登录2.4 卸载程序 3. 镜像安装3.1 下载镜像3.2 安装镜像3.3 登录 0. 界面预览 http://myfs.f3322.net…...

内网渗透神器CobaltStrike之权限提升(七)
Uac绕过 常见uac攻击模块 UAC-DLL UAC-DLL攻击模块允许攻击者从低权限的本地管理员账户获得更高的权限。这种攻击利用UAC的漏洞,将ArtifactKit生成的恶意DLL复制到需要特权的位置。 适用于Windows7和Windows8及更高版本的未修补版本 Uac-token-duplication 此攻…...

使用haproxy搭建web架构
haproxy HAProxy是一个免费的负载均衡软件,可以运行于大部分主流的Linux操作系统上。 HAProxy提供了可以在七层和四层两种负载均衡能力,它可以提供高可用性、负载均衡、及基于TCP和HTTP应用的代理。适用于负载大的Web站点,在运行在硬件上可…...

Java基础之IO流File类创建及删除
1.File类概述及构造方法 2.File类创建功能 文件创建成功! 如果文件不存在,就创建文件,并返回true 如果文件存在,就不创建文件,并返回false 如果文件夹不存在,就创建文件夹,并返回true 如果文件…...

高速道路监控:工业路由器助力高速监控远程管理与维护
工业路由器在物联网应用中扮演着重要的角色。物联网的发展使得大量设备和传感器能够互联互通,而工业路由器作为连接这些设备和网络的中间桥梁,承担着数据传输和安全管理的重要责任。 工业路由器能够为高速监控提供网络功能,实现户外无线网络部…...

【校招VIP】前端基础之post和get
考点介绍: get和post 是网络基础,也是每个前端同学绕不过去的小问题,但是在校招面试中很多同学在基础回答中不到位,或者倒在引申问题里,就丢分了。 『前端基础之post和get』相关题目及解析内容可点击文章末尾链接查看…...

如何合理设计API接口?
本规范仅适用于由服务器端发起调用请求、POST提交数据以及GET请求文本数据结果的API,统一采用UTF-8编码规则,采用JSON格式响应。 URL定义 API 服务接口应提供REST风格的HTTP(HTTPS) 接口: {protocol}://{domain}:{port}/{app}/{controller}/{action}?{query} 变量 含义 示…...

Jsp 解决out.print()输出多出空行
一、原因 在 JSP 中,HTML 标签和 JSP 指令之外的内容会被当作文本处理,包括空行、空格和制表符等。当 JSP 引擎解析 JSP 页面时,会将这些文本内容原封不动地输出到响应中。 http响应 二、解决方法 在Jsp页面最前端添加 <% page trimDir…...

SMC状态机 讲解2 从模型到SMC
SMC状态机 讲解2 从模型到SMC 1、实例化有限状态机(FSM)2、简单转换 Simple Transition3、外部环回转换 External Loopback Transition4、内部环回转换 Internal Loopback Transition5、转换动作6、转换Guard7、转换参数8、Entry 和 Exit动作9、Push 转换10、Pop转换…...

MyBatis-Plus的使用
MyBatis-Plus 1、mybatis-plus介绍 官网:https://baomidou.com/ MyBatis-Plus (简称 MP)是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。MyBatis-Plus提供了通用的mapper…...

板卡设计+硬件每日学习十个知识点(44)23.8.24 (检测单元设计,接口部分设计,板卡电源输入设计,电源检测电路)
文章目录 1.检测单元介绍(使用GD32单片机)2.GD32的最小系统板3.GD32的温度监测4.GD32的电压监测和电流监测5.GD32的布线6.接口部分设计7.板卡电源输入设计8.电源检测电路 1.检测单元介绍(使用GD32单片机) 答: 首先要为…...

jmeter HTTP信息头管理器
首先,打开JMeter并创建一个新的测试计划。右键单击测试计划,选择"添加" > “线程组”,然后在线程组上右键单击,选择"添加" > “Sampler” > “HTTP请求”。 在HTTP请求中填写服务器的URL和其他必要…...

各种中间件的默认端口
面试时会忘记个别中间件端口 docker:2375 nacos:8848 redis:6379 rabbitMq: 5672(后台配置的端口)15672(web管理界面)账号:guest15674(web STOMP插件):通过WebSocket…...

leetcode303. 区域和检索 - 数组不可变(java)
前缀和数组的应用 区域和检索 - 数组不可变题目描述前缀和数组代码演示 区域和检索 - 数组不可变 难度 - 简单 原题链接 - 区域和检索 - 数组不可变 题目描述 给定一个整数数组 nums,处理以下类型的多个查询: 计算索引 left 和 right (包含 left 和 righ…...

PHP 安装Composer,vue前端依赖包
电脑安装Composer 官网下载:https://getcomposer.org/Composer-Setup.exe 后端安装: 检查是否安装依赖: 安装Composer install 或 Composer i 前端安装: yarn install 安装依赖...

OpenCV项目开发实战--基于Python/C++实现鼠标注释图像和轨迹栏来控制图像大小
鼠标指针是图形用户界面 (GUI) 中的关键组件。没有它,您就无法真正考虑与 GUI 进行交互。那么,让我们深入了解 OpenCV 中鼠标和轨迹栏的内置函数。我们将演示如何使用鼠标来注释图像,以及如何使用轨迹栏来控制图像的大小 我们将使用下图来演示 OpenCV 中鼠标指针和轨迹栏功能…...

❤ Vue使用Eslint检测报错问题和解决
❤ Vue使用Eslint检测报错问题和解决 1、 关闭Eslint检测 关闭ESLint语法检测即可:具体步骤如下: 第一步我们打开setting设置: 打开左上角的file,然后点击setting 接下来进入setting以后我们来看下面操作: eol-l…...

解决运行在微信小程序中报[ app.json 文件内容错误] app.json: app.json 未找到(env: Windows,mp,1.05.2204
找到project.config.json文件夹 添加 "miniprogramRoot": "unpackage/dist/dev/mp-weixin/", 即可...