JavaScript 进阶 第四天

  • 深浅拷贝
  • 异常处理
  • 处理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))

节流防抖总结

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Centos 8 网卡connect: Network is unreachable错误解决办法

现象1、ifconfig没有ens160配置 [testlocalhost ~]$ ifconfig lo: flags73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopba…

windows安装使用RocketMQ常见问题,及springboot整合

win安装rocketmq 官网下载二进制包&#xff1a;https://rocketmq.apache.org/download 解压到不包含中文及空格的目录&#xff0c;配置环境变量 ROCKETMQ_HOME4. 修改runbroker.cmd和runserver.cmd文件 文件地址在rocketmq安装目录下的bin文件夹中。 如果不修改可能会遇见以…

opencv进阶03-图像与鼠标的交互示例

在处理图像时&#xff0c;可能需要与当前正在处理的图像进行交互。OpenCV 提供了鼠标事件&#xff0c;使用户可以通过鼠标与图像交互。鼠标事件能够识别常用的鼠标操作&#xff0c;例如&#xff1a;针对不同按键的单击、双击&#xff0c;鼠标的滑动、拖曳等。 例如&#xff0c;…

windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】

windows搭建WebDAV服务&#xff0c;并内网穿透公网访问【无公网IP】 文章目录 windows搭建WebDAV服务&#xff0c;并内网穿透公网访问【无公网IP】1. 安装IIS必要WebDav组件2. 客户端测试3. cpolar内网穿透3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表3.4 浏览器访…

数字化转型能带来哪些价值?_光点科技

随着科技的迅猛发展&#xff0c;数字化转型已成为企业和组织的一项重要战略。它不仅改变了商业模式和运营方式&#xff0c;还为各行各业带来了诸多新的机遇和价值。在这篇文章中&#xff0c;我们将探讨数字化转型所能带来的价值。 数字化转型能够显著提升效率和生产力。通过引入…

Ubuntu 20.04使用Livox mid 360 测试 FAST_LIO

前言 Livox mid360需要使用Livox-SDK2&#xff0c;而非Livox-SDK&#xff0c;以及对应的livox_ros_driver2 。并需要修改FAST_LIO中部分代码。 1. 安装Livox-SDK2 参考官方教程。 1.1. 安装CMake sudo apt install cmake1.2. 安装编译Livox-SDK2 git clone https://github…

C++多态

一、多态的定义及实现 多态是在不同继承关系的类对象&#xff0c;去调用同一函数&#xff0c;产生了不同的行为。比如Student继承了 Person。Person对象买票全价&#xff0c;Student对象买票半价。 构成多态的两个条件&#xff1a; 1、必须通过基类的指针或者引用调用虚函数…

废品回收抢单派单小程序开源版开发

废品回收抢单派单小程序开源版开发 用户注册和登录&#xff1a;用户可以通过手机号码注册和登录小程序&#xff0c;以便使用废品回收抢单派单功能。废品回收订单发布&#xff1a;用户可以发布废品回收订单&#xff0c;包括废品种类、数量、回收地点等信息。废品回收抢单&#…

【python知识点】锦集

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/132368704 出自【进步*于辰的博客】 相关博文&#xff1a;【python细节、经验】锦集。 注&#…

陕西科技大学改考408!附考情分析

改考信息 8月14日&#xff0c;陕西科技大学公布了2024年硕士研究生招生目录&#xff08;初稿&#xff09;&#xff0c;其中不难发现083500软件工程初试专业课由819数据结构改为408计算机学科专业基础 图片&#xff1a;陕西科技大学24专业目录-软件工程学硕 https://yjszs.sus…

MySQL数据库概述

MySQL数据库概述 1 SQL SQL语句大小写不敏感。 SQL语句末尾应该使用分号结束。 1.1 SQL语句及相关操作示例 DDL&#xff1a;数据定义语言&#xff0c;负责数据库定义、数据库对象定义&#xff0c;由CREATE、ALTER与DROP三个语法所组成DML&#xff1a;数据操作语言&#xff…

【C++】 使用红黑树模拟实现STL中的map与set

文章目录 前言1. 对之前实现的红黑树进行一些补充和完善1.1 析构1.2 查找 2. STL源码中map和set的实现3. 改造红黑树封装map和set3.1 红黑树结构修改3.2 map、set的结构定义3.3 insert的封装3.4 insert测试3.5 发现问题并解决3.6 红黑树迭代器实现3.7 封装set和map的迭代器并测…

svg图片如何渲染到页面,以及svg文件的上传

svg图片渲染到页面的几种方式 背景&#x1f7e1;require.context获取目录下的所有文件&#x1f7e1;方式1: 直接在html中渲染&#x1f7e1;方式: 发起ajax请求&#xff0c;获取SVG文件 背景 需要实现从本地目录下去获取所有的svg图标进行预览&#xff0c;将选中的图片显示在另…

报道|新鲜出炉!INFORMS公布六位新任期刊主编

推文作者&#xff1a;徐思坤 编者按 INFORMS旗下的六本期刊&#xff0c;Management Science、Operations Research、Service Science、Tutorials in OR、INFORMS Analytics Collection&#xff0c;以及Transportation Science的新任主编公布&#xff0c;并将于2024年1月1日正式…

基于微信小程序的上门维修评价系统_22c7h-

随着科学研究的不断深入&#xff0c;有关上门维修的各种信息量也在成倍增长。面对庞大的信息量&#xff0c;就需要有上门维修系统来提高管理工作的效率。通过这样的系统&#xff0c;我们可以做到信息的规范管理和快速查询&#xff0c;从而减少了管理方面的工作量。 建立基于微信…

CentOS ens160 显示disconnected

使用nmcli device查看网卡状态&#xff0c;显示如图&#xff1a; 检查宿主机系统VMware DHCP Sevice和VMware NAT Sevice服务是否正常运行。 右键点击我的电脑管理按钮&#xff0c;打开计算机管理点击服务

MyBatis的基本入门及Idea搭建MyBatis坏境且如何一步骤实现增删改查(CRUD)---详细介绍

一&#xff0c;MaBatis是什么&#xff1f; 首先是一个开源的Java持久化框架&#xff0c;它可以帮助开发人员简化数据库访问的过程并提供了一种将SQL语句与Java代码进行解耦的方式&#xff0c;使得开发人员可以更加灵活地进行数据库操作。 1.1 Mabatis 受欢迎的点 MyBatis不仅是…

用于优化开关性能的集成异质结二极管的4H-SiC沟道MOSFET

标题&#xff1a;4H-SiC Trench MOSFET with Integrated Heterojunction Diode for Optimizing Switching Performance 摘要 本研究提出了一种新型的4H-SiC沟道MOSFET&#xff0c;其在栅槽底部集成了异质结二极管&#xff08;HJD-TMOS&#xff09;&#xff0c;并通过TCAD模拟进…

【vim 学习系列文章 5 - cscope 过滤掉某些目录】

文章目录 cscope 过滤目录介绍 cscope 过滤目录介绍 第一步创建自己的cscope脚本~/.local/bin/cscope.sh&#xff0c;如下&#xff1a; function my_cscope() {CODE_PATHpwdecho "$CODE_PATH"echo "start cscope...."if [ ! -f "$CODE_PATH/cscope.…

编织梦想:SpringBoot AOP 教程与自定义日志切面完整实战

什么是 AOP AOP 是指通过预编译方式和运行期动态代理的方式&#xff0c;在不修改源代码的情况下对程序进行功能增强的一种技术。AOP 不是面向对象编程&#xff08;OOP&#xff09;的替代品&#xff0c;而是 OOP 的补充和扩展。它是一个新的维度&#xff0c;用来表达横切问题&a…