JavaScript 进阶(面试必备)--charater4


文章目录

  • 前言
  • 一、深浅拷贝
    • :one: 浅拷贝
    • :two:深拷贝
  • 二、异常处理
    • :one: throw 抛异常
    • :two: try /catch 捕获异常
    • :three:debugger
  • 三、处理this
    • `this指向` :one:普通函数this指向
    • `this指向` :two: 箭头函数this指向
    • 3.2 改变this
      • :one: call()
      • :two: apply()
      • :three: bind()
  • 四、性能优化
    • :one: 节流 throttle
    • :two:防抖 debounce
    • js 库lodash 实现节流和防抖
  • 总结


前言

这章学习目标:

  1. 深入this学习,知道如何判断this指向和改变this 指向
  2. 知道在JS中如何处理异常,学习深浅拷贝,理解递归。

提示:以下是本篇文章正文内容,下面案例可供参考

一、深浅拷贝

1️⃣ 浅拷贝

对于字符串类型,浅复制是对值的复制,对于对象来说,浅复制是对对象地址的复制,并没有开辟新的栈,也就是复制的结果是对两个对象指向同一个地址,修改其中一个对象的属性,则另外一个对象的属性也会改变。简单的来说,拷贝的是地址。
JavaScript 进阶(面试必备)--charater4_第1张图片
拷贝对象之后,里面的属性值是简单数据类型直接拷贝值
如果属性值是引用数据类型则拷贝的是地址

// 一个pink对象
const pink ={
	name:'pink老师'age:18
}
const red = pink
console.log(red)//{name:'pink老师',age:18}

red.name='red老师'
console.log(red)//{name:'red者师',age:18}
//但是pink对象里面的name值也发生了变化
console.log(pink)//[name:'red老师',age:18}

⭕️常用方法
拷贝对象:Object.assign() 或者展开符 {…obj } 拷贝对象

  const obj = {
      uname: 'pink',
      age: 18
    }
    const o = obj
    console.log("o",o)
    o.age = 20
    console.log(" o.age",o)
    console.log("obj",obj)
 const obj = {
      uname: 'pink',
      age: 18
    }
 const o = {}
    Object.assign(o, obj)
    o.age = 20
    o.family.baby = '老pink'
    console.log(o)
    console.log(obj)

在这里插入图片描述
拷贝数组:Array.prototype.concat() 或者[…arr]

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

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

2️⃣深拷贝

⭕️ 常见方法:

  1. 通过递归实现深拷贝
    如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
    递归函数的作用和循环效果类似
    由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件 return
    在这里插入图片描述
    let i = 1
    function fn() {
      console.log(`这是第${i}`)
      if (i >= 6) {
        return
      }
      i++
      fn()// 函数内部调用自己
    }
    fn()

2. js库lodash 里clone Deep内部实现深拷贝

  <!-- 先引用 -->
  <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)

JavaScript 进阶(面试必备)--charater4_第2张图片
3. 通过JSON.stringify()实现

    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)

JavaScript 进阶(面试必备)--charater4_第3张图片

二、异常处理

1️⃣ throw 抛异常

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

  1. throw 抛出异常信息,程序也会终止执行
  2. throw 后面跟的是错误提示信息
  3. Error 对象配合 throw 使用,能够设置更详细的错误信息

function counter(x,y){
	if(!x||!y){
		throw new Error('参数不能为空')
  }
  return x+y
}
counter()

2️⃣ try /catch 捕获异常

  1. try…catch 用于捕获错误信息。
  2. 将预估可能发生错误的代码写在 try 代码段中。
  3. 如果 try 代码段中出现错误后,会执行 catch 代码段,并截获到错误信息
  4. finally 不管是否有错误,都会执行。
   function fn() {

      try {
        // 可能预估有问题的代码写到这里
        const p = document.querySelector('.p')
        p.style.color = 'red'
      } catch (err) {
        console.log(err.message)
        // 中断
        // return
        throw new Error('你是不是把选择器写错了')
      } finally {
        alert('执行')
      } 
      console.log(111)
    }
    fn()

3️⃣debugger

我们可以通过try / catch 捕获错误信息(浏览器提供的错误信息)
JavaScript 进阶(面试必备)--charater4_第4张图片

三、处理this

不同的应用场合 this 的取值可能会有意想不到的结果,在此我们对以往学习过的关于【 this 默认的取值】情况进行归纳和总结。知道动态指定函数 this 值的方法。

this指向 1️⃣普通函数this指向

普通函数的调用方法决定了this的值,即【谁调用this 就指向谁】

 // 普通函数:  谁调用我,this就指向谁
1. console.log(this)  // window
     function fn() {
      console.log(this)  // window    
    }
    window.fn()
    window.setTimeout(function () {
      console.log(this) // window 
    }, 1000)

 2.document.querySelector('button').addEventListener('click', function () {
      console.log(this)  // 指向 button
    })
 
 3.const obj = {
      sayHi: function () {
        console.log(this)  // 指向 obj
      }
    }
    obj.sayHi()

this指向 2️⃣ 箭头函数this指向

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

  1. 箭头函数会默认帮我们绑定外层this的值,所有在箭头函数中this的值和外层this是一样的
  2. 箭头函数中的this引用的就是最近作用域中的this
  3. 向外层作用域中,一层一层查找this,直到有this的定义
1.
 console.1og(this)//此处为window
//箭头函数
const sayHi = function(){
    console.log(this)
    //该箭头函数中的this为函数声明环境中this一致
}


2.    //普通对象
const user={
    name:'小明',
    //该箭头函数中的this为函数声明环境中this一致
    walk:()=>{
      console.log(this)
    }
}

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

//D0M 节点
const btn=document.queryselector('.btn')
//箭头函数此时this指向了window
btn.addEventListener('click',()=>
    console.log(this)
})

//普通函数此时this指向了DoM对象
btn.addEventListener('click',function (){
    console.log(this)
})

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

  1. 函数内不存在this,沿用上一级的this
  2. 不适应构造函数,原型函数,dom事件函数等等。
  3. 需要用上层this的地方。

3.2 改变this

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

1️⃣ call()

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

fun.call(thisArg, arg1, arg2, ...)

thisArg:在fun 函数运行时指定的this
arg1,arg2:传递参数
返回值就是函数的返回值,因为它就是调用函数。

    const obj = {
      uname: 'pink'
    }
    function fn(x, y) {
      console.log(this) // window.object
      console.log(x + y)// 3
    }
    // 1. 调用函数  
    // 2. 改变 this 指向
    fn.call(obj, 1, 2)

2️⃣ apply()

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

  1. 调用函数
    2. 改变this指向
 fn.apply(this指向谁, [数组参数])
    const obj = {
      age: 18
    }
    function fn(x, y) {
      console.log(this) // Object{age: 18}
      console.log(x + y)// 3
    }
   
    fn.apply(obj, [1, 2])
    //  返回值   本身就是在调用函数,所以返回值就是函数的返回值

thisArg:在fun函数运行时指定的 this 值
argsArray:传递的值,必须包含在数组里面
返回值就是函数的返回值。因为它就是调用函数
apply 主要跟数组有关系,比如使用Math.max() 求数组的最大值。

1.const max = Math.max(1,2,3)
2.const arr =[100 , 45 ,55]
const max =Math.math.apply(Math,arr)
const min =Math.math.apply(Matg,arr)
console.log(max,min)
3. console.log(Math.max(...arr))

3️⃣ bind()

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

fun.bind(thisArg, arg1, arg2, ...)

thisArg:在 fun 函数运行时指定的 this 值
arg1,arg2:传递的其他参数
返回由指定的this 值和初始化参数改造的 原函数
如果不想调用函数来改变this指向时,可以使用bind,比如改变定时器内部的this 指向

  // 普通函数
  function sayHi() {
    console.log(this)
  }
  let user = {
    name: '小明',
    age: 18
  }
  // 调用 bind 指定 this 的值
  let sayHello = sayHi.bind(user);
  // 调用使用 bind 创建的新函数
  sayHello()

注:bind 方法创建新的函数,与原函数的唯一的变化是改变了 this 的值。

四、性能优化

1️⃣ 节流 throttle

节流就指连续触发事件但是在n秒中只执行一次函数。就如等到上一个人完成动作,才能进行下一个人执行。
开发使用场景小米轮播图点击效果鼠标移动页面尺寸缩放resize滚动条滚动 就可以加节流。
如果一张轮播图完成切换需要300ms,不加节流效果,快速点击,就会快速切换。

2️⃣防抖 debounce

防抖就是触发事件后在n秒内函数只能执行一次,如果在n秒内再次触发事件,则会重新计算

开发使用场景- 搜索框防抖
假设输入就可以发送请求,但是不能每次输入都去发送请求,输入比较快发送请求会比较多,我们设定一个时间,假如300ms, 当输入第一个字符时候,300ms后发送请求,但是在200ms的时候又输入了一个字符,则需要再等300ms 后发送请求。

js 库lodash 实现节流和防抖

lodash文档

<div class="box"></div>
<script src="./lodash.min.js"></script>
    function mouseMove() {
      box.innerHTML = ++i
      // 如果里面存在大量操作 dom 的情况,可能会卡顿
    }
    box.addEventListener('mousemove', mouseMove)
    // lodash 节流写法
    box.addEventListener('mousemove', _.throttle(mouseMove, 500))
    // lodash 防抖的写法
    box.addEventListener('mousemove', _.debounce(mouseMove, 500))

总结

本章深入学习里this学习,知道如何判断this指向和改变this指向,深浅拷贝,递归等知识点,在面试备考中希望能帮助到大家❤️

你可能感兴趣的:(见习工程师,javascript,前端,vue.js)