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

1深浅拷贝

1.1浅拷贝

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

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

JS深浅拷贝、异常处理、处理this、性能优化_第1张图片

因为他们的存储规则  

JS深浅拷贝、异常处理、处理this、性能优化_第2张图片

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

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

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

常见的拷贝方法:

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

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

JS深浅拷贝、异常处理、处理this、性能优化_第3张图片

 JS深浅拷贝、异常处理、处理this、性能优化_第4张图片

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

JS深浅拷贝、异常处理、处理this、性能优化_第5张图片

总结:

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

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

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

 浅拷贝怎么理解?

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

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

1.2深拷贝

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

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

常见方法:

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

②lodash/cloneDeep 

③通过JSON.stringify()实现

函数递归:

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

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

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

JS深浅拷贝、异常处理、处理this、性能优化_第6张图片

 函数递归的方法?

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 处停止执行。

类似于断点调试哦

JS深浅拷贝、异常处理、处理this、性能优化_第7张图片

 3处理this

3.1this 指向

3.1.1普通函数this指向

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

JS深浅拷贝、异常处理、处理this、性能优化_第8张图片

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

3.1.2箭头函数this指向

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

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

JS深浅拷贝、异常处理、处理this、性能优化_第9张图片

 注意情况1

在开发中【使用箭头函数前需要考虑函数中 this 的值】,事件回调函数使用箭头函数时,this 为全局的 window
因此DOM事件回调函数 如果里面需要 DOM对象的this,则不推荐使用箭头函数 JS深浅拷贝、异常处理、处理this、性能优化_第10张图片

 注意情况2

同样由于箭头函数 this 的原因,基于原型的面向对象也不推荐采用箭头函数
JS深浅拷贝、异常处理、处理this、性能优化_第11张图片

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

3.2改变this

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

3.2.1 call()

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

 JS深浅拷贝、异常处理、处理this、性能优化_第12张图片

 JS深浅拷贝、异常处理、处理this、性能优化_第13张图片

JS深浅拷贝、异常处理、处理this、性能优化_第14张图片

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

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

3.2.2apply()

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

第一个参数可以设置null

JS深浅拷贝、异常处理、处理this、性能优化_第15张图片

 JS深浅拷贝、异常处理、处理this、性能优化_第16张图片

 call和apple的区别是什么?

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

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

3.2.3bind()重点

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

JS深浅拷贝、异常处理、处理this、性能优化_第17张图片

 总结:

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

区别点:

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

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

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

主要应用场景

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

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

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

4性能优化

4.1防抖

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

JS深浅拷贝、异常处理、处理this、性能优化_第18张图片

4.2节流

JS深浅拷贝、异常处理、处理this、性能优化_第19张图片

JS深浅拷贝、异常处理、处理this、性能优化_第20张图片

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

你可能感兴趣的:(前端,javascript,前端,开发语言)