JavaScript 进阶 第四天

news2024/11/24 10:31:18
  • 深浅拷贝
  • 异常处理
  • 处理this
  • 性能优化

一. 深浅拷贝

深浅拷贝只针对引用类型

1.1 浅拷贝

  • 拷贝的是地址
  • 常见方法

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

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

  • 浅拷贝存在的问题

      ① 简单数据类型拷贝的是值,引用数据类型拷贝的是地址

      ② 赋值的时候不会影响原来的值,如果是简单数据类型拷贝值,引用数据类型拷贝的是地址

      ③ 如果是单层对象,就没问题,如果是多层对象就有问题

 改变o 的值不会影响obj的值

 如果是多层对象,改变o的值就会影响到obj的值

  •  直接赋值和浅拷贝有什么区别

     ① 直接赋值,只要是对象,就会互相影响,因为会直接拷贝对象栈里面的地址

     ② 浅拷贝如果是一层对象,不会相互影响,如果是多层对象,还是会互相影响

  • 浅拷贝怎么理解

    ① 拷贝对象后,里面的属性值是简单数据类型直接拷贝值

    ② 如果属性值是引用数据类型则拷贝的是地址

1.2 深拷贝

  • 深拷贝:拷贝的是对象,不是地址
  • 常见方式

        ① 通过递归实现深拷贝

        ② loadash/cloneDeep

        ③ 通过JSON.stringify()实现

  • 通过递归实现深拷贝

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

       ② 就是自己调自己

       ③ 递归容易发生“栈溢出"错误,所以必须要加退出条件return

let i = 1
        function fn () {
            console.log(`这是第${i}次`)
            if (i >= 6) {
                return
            }
            i++
            fn()
        }
        fn()
  • 递归实现
        const obj = {
            uname :'pink',
            age: 18,
            hobby:['乒乓球', '足球'],
            family: {
                baby: '小pink'
            }
        }
        const o = {}

        function deepCopy(newObj, oldObj) {
            // 在代码中直接打断点
            debugger
            for (let k in oldObj) {
                // 处理数组的问题
                // 一定先写数组,再写对象,因为数组属于对象
                if (oldObj[k] instanceof Array) {
                    newObj[k] = []
                    deepCopy(newObj[k], oldObj[k])
                } else if (oldObj[k] instanceof Object) {
                    newObj[k] = {}
                    deepCopy(newObj[k], oldObj[k])
                } else {
                    newObj[k] = oldObj[k]
                }
                // k 属性名  属性值 oldObj[k]
            }
        }
        deepCopy(o, obj)
        o.age = 20
        o.hobby[0] = '篮球'
        o.family.baby = '小hi'
        console.log(o)
        console.log(obj)

  • 使用lodash实现深拷贝
  <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>
  • 利用JSON.stringfy 
        const obj = {
            uname :'pink',
            age: 18,
            hobby:['乒乓球', '足球'],
            family: {
                baby: '小pink'
            }
        }

        // 1.先转换为字符串,然后再转回对象,就会生成一个新的对象,跟原来的对象没有关系,
        // 修改里面的值不会影响原来的数据
        const o = JSON.parse(JSON.stringify(obj))
        console.log(o)
        o.family.baby = '123'
        console.log(obj)

二.异常处理

  • throw抛异常
  • try/catch 捕获异常
  • debugger

2.1 throw抛异常

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

  • throw 抛出异常信息,程序也会终止执行
  • throw 后面跟的是错误提示信息
  • Error对象配合throw使用,能够设置更详细的错误信息
        function fn(x, y) {
            if (!x || !y) {
                // throw '没有参数传递进来'
                // 精确到行
                throw new Error('没有参数传递进来')
                
            }
            return x + y
        }

2.2 catch捕获异常

① 代码示例

        function fn(){
            try {
                const p = document.querySelector('.p')
                p.style.color = 'red'
            } catch (err) {
                // 只是拦截错误,提示浏览器提供的错误信息,但是不中断程序的执行
                console.log(err.message)
                // 加return 中断程序
                // return
                throw new Error('选择器错误了')
            }
            // 不管程序对不对,一定会执行的代码
            finally {
                alert('弹出对话框')
            }
            // 
            console.log(111)
        }
        fn()

② 说明

  • 可能发送错误的代码写到try中
  • 如果try中的代码出现错误后,会执行catch中的代码段,并截获到错误信息
  • catch会拦截错误,提示浏览器提供的错误信息,但是不中断程序的执行
  • finally无论程序对错,一定会执行

2.3 debugger

作用:断点调试

三.this指向 

3.1 普通函数的this指向

  • 普通函数的调用方式决定了this的值,即【谁调用this的值就指向谁】
  • 普通函数没有明确调用者时this的值为window, 严格模式(use strict)下没有调用者时this的值为undefined

3.2 箭头函数的this指向

  • 箭头函数中的this与普通函数完全不同,也不受调用方式的影响,事实上箭头函数中并不存在this
  • 箭头函数中的this会默认绑定上一层的this值
  • 会向外层作用域一层一层查找this, 直到有this的定义

3.3 注意情况

  • DOM事件回调函数如果里面需要DOM对象的this, 不推荐使用箭头函数
  • 基于原型的面向对象也不推荐采用箭头函数
  • 构造函数,原型函数,DOM事件等不适用
  • 适用于需要使用上层this的地方

3.4 改变this的指向

  • call()
  • apply()
  • bind()

1.call()

  • 使用call方法调用函数,同时执行被调用函数中this的值
  • 语法:fun.call(thisArg, arg1, arg2)
  • 返回值就是函数的返回值,因为它就是调用函数
        const obj = {
            uname: 'pink'
        }
        function fn (x, y) {
            console.log(x + y)
            console.log(this)   // obj
        }

        // 1.调用函数
        // 2.改变this指向
        fn.call(obj, 1, 2)

2.apply()

  • 使用apply方法调用函数,同时指定被调用函数中this的值
  • 语法: fun.apply(thisArg, [argsArray])
  • thisArg:在fun函数运行时指定的this值
  • argsArray:传递的值,必须包含在数组里面
  • 返回值就是函数的返回值,因为它就是调用函数
  • apply主要跟数组有关系,比如使用Math.max() 求数组的最大值
        const obj = {
            uname: 'pink'
        }
        function fn (x, y) {
            console.log(this)
            console.log(x + y)
        }
        // 1.调用函数   2.改变this指向   3.第三个参数要放一个数组
        fn.apply(obj, [1, 2])

求数组最大值

const arr = [2, 4, 5]
const max = Math.max.apply(Math, arr)
console.log(max)
console.log(Math.max(...arr))

3.bind()

  • bind() 方法不会调用函数,但是能改变函数内部this指向
  • 语法:fun.bind(thisArg, arg1, arg2)
  • thisArg:在 fun函数运行时指定this的值
  • arg1, arg2:传递的其他参数
  • 返回由指定的this值和初始化参数改造的 原函数拷贝(新函数)
  • 只是向改变this指向,并不想调用这个函数的时候,可以使用bind
  • 如下代码,如果不调用fun的话只是去调用bind,fn函数是不会调用的
        const obj = {
            uname: 'pink'
        }
        function fn () {
            console.log(this)
        }

        // 返回值是个函数,但是这个函数里面的this是更改过的obj
        const fun = fn.bind(obj)
        // console.log(fun)
        fun()

4. 相同点

  • 都可以改变函数内部的this指向

5.区别点

  • call 和 apply 会调用函数,并且改变函数内部this指向
  • call和apply传递的参数不一样,call传递参数arg1, arg2...的形式,apply 必须传数组形式
  • bind不会调用函数,可以改变函数内部this指向

6.主要应用场景

  • call 调用函数并且可以传递参数
  • apply 经常跟数组有关系,比如借助于数学对象实现数组最大值最小值
  • bind 不调用函数,但还想改变this指向

四. 防抖

  • 防抖:单位时间内,频发触发事件,只执行最后一次

  • 使用场景

     ① 搜索框搜索输入,只需用户最后一次输入完,再发送请求

     ② 手机号,邮箱验证输入检测

  • 需求实现:鼠标在盒子上移动,鼠标停止500ms之后,里面的数字才会变化 +1

      ① losash 提供的防抖来处理

 const box = document.querySelector('.box')
    let i = 1
    function mouseMove() {
      box.innerHTML = i++
      // 如果里面存在大量消耗性能的代码,比如dom操作,数据处理,可能造成卡顿
    }

box.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() // 加小括号调用
        }, t)
      }
    }
 box.addEventListener('mousemove', debounce(mouseMove, 500))

  五. 节流

  • 单位时间内,频繁触发事件,只执行一次
  • 举例:王者荣耀冷却技能
  • 使用场景:鼠标移动mousemove 页面尺寸缩放resize 滚动条滚动scroll
  • 实现方式

     ① 使用lodash实现

const box = document.querySelector('.box')
    let i = 1
    function mouseMove() {
      box.innerHTML = i++
    }
    // // 500毫秒之内只会执行一次
    box.addEventListener('mousemove', _.throttle(mouseMove, 500))

 ② 自己写一个节流函数

    // 1.声明一个定时器变量
    // 2.当鼠标每次滑动都先判断是否有定时器,如果有定时器就不开启
    // 3.如果没有定时器则开启定时器
    // 4.定时器里面调用要执行的函数
    // 5.定时器里面要把定时器清空
    function throttle(fn, t) {
        let timer = null
        return function() {
            if (!timer) {
                timer = setTimeout(function() {
                    fn()
                    // 清空定时器
                    // 不能使用clearTimeout(timer), 在setTimeout中无法使用clearTimeout来清除定时器
                    timer = null
                }, t)
            }
        }
    }
    box.addEventListener('mousemove', throttle(mouseMove, 500))

节流防抖总结

 

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

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

相关文章

蓝桥杯每日N题(杨辉三角形)

大家好 我是寸铁 希望这篇题解对你有用&#xff0c;麻烦动动手指点个赞或关注&#xff0c;感谢您的关注 不清楚蓝桥杯考什么的点点下方&#x1f447; 考点秘籍 想背纯享模版的伙伴们点点下方&#x1f447; 蓝桥杯省一你一定不能错过的模板大全(第一期) 蓝桥杯省一你一定不…

Hbase的列式存储到底是什么意思?一篇文章让你彻底明白

一、 HBase 定义 Apache HBase™ 是以 hdfs 为数据存储的&#xff0c;一种分布式、可扩展的 NoSQL 数据库。 二、 HBase 数据模型 HBase 的设计理念依据 Google 的 BigTable 论文&#xff0c;论文中对于数据模型的首句介绍。 Bigtable 是一个稀疏的、分布式的、持久的多维排…

性能优化的重要性

性能优化的重要性 性能优化的重要性摘要引言注意事项代码示例及注释性能优化的重要性 性能优化的重要性在 Java 中的体现响应速度资源利用效率扩展性与可维护性并发性能合理的锁策略线程安全的数据结构并发工具类的应用避免竞态条件和死锁 总结代码示例 博主 默语带您 Go to Ne…

【Java】常用工具——字符串

1. String的创建 String s1 "Katnisss Blog"; String s2 new String(); //空的字符串 String s3 new String("Katnisss Blog");2. String的常用方法 方法解释int length()返回字符串长度int indexOf(char c)返回字符c出现的第一个位置int indexOf(Str…

十、RabbitMQ集群

一、clustering 1、 使用集群的原因 单台RabbitMQ遇到内存崩溃、机器故障等情况会导致服务不可用单台RabbitMQ只能满足每秒1000条的消息吞吐量 2、搭建步骤 1、准备三台虚拟机 2、修改3台机器的主机名称 分别为node1、node2、node3 vi /etc/hostname 3、配置节点的hosts文…

【第三阶段】kotlin语言中的数字安全转换函数(String转Int)

字符串有整形相关的转换&#xff0c;尽量使用toIntOrNull&#xff08;&#xff09;函数 fun main() {//String转Intvar num1"666"println(num1.toInt())//Double不能自动转换为Int,会崩溃&#xff0c;解决崩溃如下&#xff1a;toIntOrNull()如果转换失败会转为nullv…

ATF(TF-A) 威胁模型汇总

安全之安全(security)博客目录导读 目录计划如下&#xff0c;相关内容补充中&#xff0c;待完成后进行超链接&#xff0c;敬请期待&#xff0c;欢迎您的关注 1、通用威胁模型 2、SPMC威胁模型 3、EL3 SPMC威胁模型 4、fvp_r 平台威胁模型 5、RSS-AP接口威胁模型 威胁建模是安全…

290页12万字数字乡村项目规划建设方案WORD

导读&#xff1a;原文《290页12万字数字乡村项目规划建设方案WORD》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 目录 第一章总体概述1 1.1.建设背景1 1.1.1.数…

马斯克又出昏招、最疯狂的举动之一

马斯克正在限制他不喜欢的新闻网站和竞争对手的流量。在 X&#xff08;原 Twitter&#xff09;上点击纽约时报、路透社、Facebook、Instagram、Threads、Bluesky 和 Substack 的链接&#xff0c;X 故意增加 5 秒钟的开启延迟。 5 秒延迟&#xff0c;新的降权举措&#xff1f; …

VisualStudio打包项目文件为.exe安装包

前言&#xff1a; 使用扩展&#xff1a;install Projects 注意事项&#xff1a;打包项目前&#xff0c;确保项目能正常运行&#xff0c;不然打包毫无意义。 一、安装扩展 打开vs软件->扩展->管理扩展->搜索install Projects->安装->重启软件 二、制作安装包&a…

抖音小程序SEO关键词布局开发文档

一、概述 抖音小程序SEO关键词布局是指在小程序中合理地安排关键词&#xff0c;以提高小程序的搜索排名和用户流量。本开发文档旨在提供关于抖音小程序SEO关键词布局的指导&#xff0c;帮助开发者有效实施关键词布局策略。 二、数据分析 在实施抖音小程序SEO关键词布局之前&a…

SOLIDWORKS镜向是什么?

在现代工程设计中&#xff0c;使用CAD软件是必不可少的。SOLIDWORKS作为一款功能强大的三维建模软件&#xff0c;提供了众多的工具和功能&#xff0c;帮助工程师以更高的效率进行设计。其中&#xff0c;SOLIDWORKS 镜向功能被广泛应用于设计过程中&#xff0c;为用户带来了许多…

园艺照明设备植物生长灯UL8800亚马逊美国站审核标准

美国是一个对安全要求非常严格的国家&#xff0c;美国本土的所有电子产品生产企业早在很多年前就要求有相关安规检测。而随着亚马逊在全球商业的战略地位不断提高&#xff0c;境外的电子设备通过亚马逊不断涌入美国市场&#xff0c;美国对境外的电子产品生产企业并没有强制性的…

08- AD/DA模/数转换

AD/DA模/数转换 8、AD/DA模/数转换8.1 AD转换注意 示例8.2 DA转换DAC转换原理&#xff1a; 8.3 PWM的DAC 8、AD/DA模/数转换 8.1 AD转换 通道引脚对照表&#xff1a; ADC的引脚&#xff1a; 规则通道和注入通道&#xff1a; 各个通道可以在单次、连续、扫描或者间断模式里…

联想拯救者笔记本Win11系统键盘无法打字解决参考方法

一位好机友新购买的联想拯救者笔记本在使用过程中突然发现整个键盘都不能使用了、不能打字、按任何按键都没有反应&#xff0c;只有鼠标能正常操作&#xff1b;那么这是什么问题呢&#xff1f;能不能是笔记本的键盘坏了呢&#xff1f;还是笔记本出现了什么故障而引起键盘失灵呢…

【微服务技术二】Feign、Gateway(路由、过滤器、跨域)的初步认知

微服务技术二 五、Feign远程调用Feign替代RestTemplate自定义Feign配置方式一&#xff1a;配置文件方式&#xff1a;方式二&#xff1a;java代码方式 Feign性能优化Feign的最佳实践* 六、Gateway网关搭建网关服务路由断言工厂Route Predicate Factory路由过滤器 GatewayFilter默…

Linux网络编程(TCP状态转换关系)

文章目录 前言一、TCP状态转换图二、TCP连接状态转换解析三、TCP断开状态转换解析四、为什么需要有2MLS时长总结 前言 本篇文章来讲解一下TCP的状态转换关系&#xff0c;学习这个状态转换关系对于我们深入了解网络编程是非常有必要的。 一、TCP状态转换图 二、TCP连接状态转换…

【数据结构OJ题】相交链表

原题链接&#xff1a;https://leetcode.cn/problems/intersection-of-two-linked-lists/description/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 看到这道题&#xff0c;很容易想到的方法就是暴力求解&#xff0c;就是将一个链表的每个结点的地址…

【Spring专题】Spring之Bean的生命周期源码解析——阶段二(一)(IOC之实例化)

目录 前言阅读准备阅读指引阅读建议 课程内容一、SpringIOC之实例化1.1 简单回顾1.2 概念回顾1.3 核心方法讲解 二、方法讲解2.1 AbstractBeanFactory#getMergedLocalBeanDefinition&#xff1a;合并BeanDefinition2.2 AbstractAutowireCapableBeanFactory#createBean&#xff…

iOS 17 测试版中 SwiftUI 视图首次显示时状态的改变导致动画“副作用”的解决方法

问题现象 精彩的 SwiftUI 动画可以让我们的 App 活灵活现、精妙绝伦。不过原本正常的动画在测试版本的 iOS 里却有着让码农持续秃头的“副作用”&#xff1a; 我们希望在视图首次显示时驱动状态改变来产生橘色小球围绕红球旋转的动画&#xff0c;红球应该始终保持在屏幕中心。…