JS深浅拷贝、异常处理、处理this、性能优化

1深浅拷贝

1.1浅拷贝

开发过程中 如果我们直接采用赋值的方法的时候会有下面的问题 

修改一个对象的赋值的时候,另一个对象的赋值也会发生改变

因为他们的存储规则  

 所以为了避免这些问题,我们产生了浅拷贝。

1.浅拷贝和深拷贝只是针对引用类型 

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

常见的拷贝方法:

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

2.拷贝数组:Array.prototype.concat() 或者[...arr] 展开运算符

 

当拷贝复杂类型数据的时候会出现 一下问题?

总结:

1.直接赋值和浅拷贝有什么区别?

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

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

 浅拷贝怎么理解?

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

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

1.2深拷贝

深浅拷贝区别:浅拷贝和深拷贝只针对引用类型

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

常见方法:

①通过递归实现深拷贝(for(k in))

②lodash/cloneDeep 

③通过JSON.stringify()实现

函数递归:

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

递归函数的作用和循环效果类似 

由于递归很容易发生‘栈溢出’的错误(也就是死循环)(stack overflow),所以必须加退出条件 return

 函数递归的方法?

let num = 1

//fn是递归函数
function fn(){
    console.log('我要打印6次')
    if(num >=  6 ){ //如果不教判定条件就会陷入栈溢出 也就是死循环

        return
    }
    num++
    fn()//函数内部调用函数自己

}
fn()

利用函数递归实现 setTimeout模拟 setInterval效果

案例 :

function fn(){
    
    const time = new Date().toLocaleString()
   
     console.log(time) 

    setTimeout(fn,1000)//定时器调用当前函数 fn调用的是fn函数
    //这里的fn =  fn();  setTimeout(function(){},1000)  fn代替了function(){}
}
fn()

1.2.1 通过递归调用 实现浅拷贝

    const oldObj = {
        uname:'red',
        age:18,
        hobby:['xx','xxx'],
        family:{
            father:1
        }
    }
//创建一个新对象 来存储数据
    const newObj={}

function deepCopy(newObj,oldObj){
    for(let k in oldObj){
      //判断老的数据类型里面 是否存在 数组类型的数据  通过instanceof
     if(oldObj[k] instanceof Array){

    //给新对象创建 一个新的属性 并且赋值给一个数组来方便存储数据
      newObj[k] = []
    //调用深拷贝函数 把刚创建的数组 和 老的数组 以实参的形式传入到函数 来赋值
      deepCopy(newObj[k],oldObj[k])
           
        //判断老的数据里面  是否存在对象类型的数据 通过instanceof
        }else if(oldObj[k] instanceof Object){

            //创建一个新的对象 属性  并且给一个对象
            newObj[k] = []

            //调用深拷贝函数 把创建的新的对象和 老数据中存储的 以实参的形式传入到函数 来拷贝
            deepCopy(newObj[k],oldObj[k])
            
    // 如果不满足以上两项条件 就是引用赋值类型 数据  可以直接赋值。
        }else{

            newObj[k] = oldObj[k];        
        }
    }



    
}

1.2.2 通过JS库lodash 里面的cloneDeep 内部实现了深拷贝

const obj = {

    uname:'pink',
    age:18,
    hobby:['篮球','足球'],
    family:{

        baby:'小pink'
    }   
    
}


//语法  _.cloneDeep(要被克隆的对象)
    const  o = _.cloneDeep(obj)
    
    o.family.baby='老pink'

1.2.3通过JSON.stringify() 方法实现

const obj = {

    uname:'pink',
    age:18,
    hobby:['篮球','足球'],
    family:{

        baby:'小pink'
    }   
    
}
// 先用json 将对象转义为字符串类型 然后再转移成 对象 存储到O 里面即可
const o = JSON.parse(JSON.stringify(obj))

console.log(o)

o.family.baby='老pink'

console.log(obj)

2异常处理

2.1throw 抛出异常

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

function counter(x,y){
    if(!x || !y){

    //throw '参数不能为空'
      
    throw new Error('参数不能为空')


    }
     return x+y


}
counter()

总结 :

①throw 抛出异常信息,程序也会终止执行

②throw 后面跟的是错误提示信息

③Error 对象配合throw 使用能够设置更详细的错误信息

2.2try/catch 捕获异常

我们可以通过try / catch 捕获错误信息(浏览器提供的错误信息)try 试试catch 拦住 finally 最后

function foo() {
    try{

    //查找 DOM 节点
    const p  = doucument.querySelector('.p')
    p.style.color  = 'red'
//  error 就像时间对象中的 e 一样 不可以省略
    } catch(error){

    //try 代码断中执行有错误时,会执行 catch代码段
    //查看错误信息
    console.log(error.message)
       ///终止代码运行
        return
    }


      finally{
        alert('执行')    
    }

   console.log('如果出现错误,我的语句不会执行')



    }
foo()

总结:

1.try...catch用于捕获错误信息

2.将预估可能发生错误的代码写在try代码段中

3.如果try代码段中出现错误后,会执行catch代码段,并截获到错误信息

4.finally 不管是否有错误 都会执行

2.3debugger

开启 debugger ,调试模式下代码会在 debugger 处停止执行。

类似于断点调试哦

 3处理this

3.1this 指向

3.1.1普通函数this指向

普通函数的调用方式决定了 this的值,即谁调用this 的值指向谁

普通函数没有明确调用者时this值为window 严格模式(use  strict 图三)下没有调用者时this的值为undefined

3.1.2箭头函数this指向

 箭头函数中的 this 与普通函数完全不同,也不受调用方式的影响,事实上箭头函数中并不存在 this

1. 箭头函数会默认帮我们绑定外层 this 的值,所以在箭头函数中 this 的值和外层的 this 是一样的
2.箭头函数中的this引用的就是最近作用域中的this
3.向外层作用域中,一层一层查找this, 直到有this的定义

 注意情况1

在开发中【使用箭头函数前需要考虑函数中 this 的值】,事件回调函数使用箭头函数时,this 为全局的 window
因此DOM事件回调函数 如果里面需要 DOM对象的this,则不推荐使用箭头函数

 注意情况2

同样由于箭头函数 this 的原因,基于原型的面向对象也不推荐采用箭头函数

总结:
1. 函数内不存在this,沿用上一级的
2.不适用
构造函数,原型函数,dom事件函数等等
3. 适用
需要使用上层this的地方
4. 使用正确的话,它会在很多地方带来方便,后面我们会大量使用慢慢体会

3.2改变this

js 中还允许指定函数中this 的指向,有三个方法可以动态指定普通函数中this的指向
 

3.2.1 call()

使用call方法调用函数,同时指定被调用函数中this的值

 

 

call作用:调用函数,并可以改变刁颖函数里面的this指向

call 里面第一个参数是指定this,其余是可以传递才参数

3.2.2apply()

appley方法调用函数,同时指定函数调用中this值  这个主要来传递数组

第一个参数可以设置null

 

 call和apple的区别是什么?

都是调用函数,都能改变this的指向

参数不一样,apply传递必须是数组

3.2.3bind()重点

bind()方法不会调用函数,但是能改变函数内部this指向的问题

 总结:

相同点:都可以改变函数内部的this指向

区别点:

call 和 apply 会调用函数 并且改变函数内部this指向

call  和 apply 传递的参数不一样,call 传递参数 aru1,aru2..形式,必须是数组【arg】

bind 不会调用函数,可以改变函数内部this指向

主要应用场景

call调用函数并且可以传递参数

apply 经常跟数组有关系,比如借助数学对象Math.来求大小值

bind 不用调用函数,但是还想改变this指向,比如改变定时器内部的this指向

4性能优化

4.1防抖

就是指触发事件后的N秒内,如果再次被触发事件就会触发当前计算函数的执行时间。

4.2节流

1. 节流和防抖的区别是?
节流: 就是指连续触发事件但是在 n 秒中只执行一次函数,比如
可以利用节流实现 1s之内 只能触发一次鼠标移动事件
防抖:如果在 n 秒内又触发了事件,则会 重新计算 函数执行时
2. 节流和防抖的使用场景是?
节流: 鼠标移动,页面尺寸发生变化,滚动条滚动等开销比较
大的情况下
防抖: 搜索框输入,设定每次输入完毕n秒后发送请求,如果期
间还有输入,则从新计算时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值