写在前面

本文为 b 站黑马程序员 pink 老师 JavaScript 教程的学习笔记。本着自己学习、分享他人的态度,分享学习笔记,希望能对大家有所帮助。推荐先按顺序阅读往期内容:\
1. JavaScript 学习笔记(Day1) \
2. JavaScript 学习笔记(Day2) \
3. JavaScript 学习笔记(Day3) \
4. JavaScript 学习笔记(Day4) \
5. JavaScript 学习笔记(Day5) \
6. JavaScript 学习笔记(WEB APIs Day1) \
7. JavaScript 学习笔记(WEB APIs Day2) \
8. JavaScript 学习笔记(WEB APIs Day3) \
9. JavaScript 学习笔记(WEB APIs Day4) \
10. JavaScript 学习笔记(WEB APIs Day5) \
11. JavaScript 学习笔记(WEB APIs Day6) \
12. JavaScript 学习笔记(JS进阶 Day1) \
13. JavaScript 学习笔记(JS进阶 Day2) \
14. JavaScript 学习笔记(JS进阶 Day3)


::: block-1

目录

  • 1 深浅拷贝
  • 2 异常处理
  • 3 处理this
  • 4 性能优化
  • 5 综合案例
  • 6 完结撒花
    :::

1 深浅拷贝

1.1 浅拷贝

P188:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=188

首先浅拷贝和深拷贝只针对引用类型

浅拷贝:拷贝的是地址

常见方法:

  1. 拷贝对象:Object.assgin() / 展开运算符 {...obj} 拷贝对象
  2. 拷贝数组:Array.prototype.concat() 或者 [...arr]
const obj = {
  uname: 'pink'
}
const o = { ...obj }
console.log(o) // {uname: 'pink'}
o.uname = 'red'
console.log(o) // {uname : 'red'}
console.log(obj) // {uname: 'pink' }

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

// 一个pink对象
const pink = {
  name: 'pink老师', 
  age: 18,
  famliy: {
    mother: 'pink妈妈'
  }
}
const red = {}
object.assign(red, pink)
console.log(red) // {name: 'pink老师', age: 18}
red.name = 'red老师'
// 更改对象里面的 family 还是会有影响
red.famliy.mother = 'red妈妈'
consoie.log(red) // {name: 'red老师', age: 18} 
// 不会影响pink对象
console.log(pink) // {name: 'pink老师', age: 18}

1.2 深拷贝

P189:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=189

首先浅拷贝和深拷贝只针对引用类型

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

常见方法:

  1. 通过递归实现深拷贝
  2. lodash/cloneDeep
  3. 通过JSON.stringify()实现

1. 通过递归实现深拷贝

函数递归:

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

  • 简单理解:函数内部自己调用自己, 这个函数就是递归函数
  • 递归函数的作用和循环效果类似
  • 由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件 return
let num = 1
// fn就是递归函数
function fn() {
  console.log('我要打印6次')
  if (num >= 6) {
    return
  }
  num++
  fn() // 函数内部调用函数自己
}
fn()
P190:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=190

通过递归函数实现深拷贝:

const o = {}
function deepCopy(newObj, oldObj) {
  for (let k in old0bj) {
    if (oldObj[k] instanceof Array) {
      new0bj[k] = []
      deepCopy(newObj[k], oldObj[k])
    } else if (oldObj[k] instanceof Object) {
      newObj[k]= {}
      deepCopy(newObj[k], oldObj[k])
    }
    else {
      newObj[k] = old0bj[k]}
    }
  }
}

2. js库lodash里面cloneDeep内部实现了深拷贝

P191:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=191
const obj = {
  uname: 'pink',
  age: 18,
  hobby: ['篮球', '足球'],
  family: {
    baby: '小pink'
  }
}
// 语法: _.cLoneDeep(要被克隆的对象)
const o = _.cloneDeep(obj)
console.log(o)
o.family.baby = '老pink'
console.log(obj)

3. 通过JSON.stringify()实现

const obj = {
  uname: 'pink',
  age: 18,
  hobby:['篮球', '足球'],
  family: {
    baby: '小pink'
  }
}
const o = JSON.parse(JSON.stringify(obj))
console.log(o)
o.family.baby = '老pink'
console.log(obj)

2 异常处理

2.1 throw 抛异常

P192:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=192

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

  1. throw 抛出异常信息,程序也会终止执行
  2. throw 后面跟的是错误提示信息
  3. Error 对象配合 throw 使用,能够设置更详细的错误信息
function counter(x, y) {
  if (!x || !y) {
    throw new Error('参数不能为空!”
  }
    return X + y
}
counter()

2.2 try /catch 捕获异常

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

  1. try...catch 用于捕获错误信息
  2. 将预估可能发生错误的代码写在 try 代码段中
  3. 如果 try 代码段中出现错误后,会执行 catch 代码段,并截获到错误信息
  4. finally 不管是否有错误,都会执行
<p>123</p>
<script>
  function fn() {
    try {
      // 可能发送错误的代码要写到 try
      const p = document.querySelector('.p')
      p.style.color = 'red'
    } catch (err) {
      // 拦截错误,提示浏览器提供的错误信息,但是不中断程序的执行
      console.log(err.message)
      throw new Error('你看看,选择器错误了吧')
      // 需要加return中断程序
      // return
    }
    finally {
      // 不管你程序对不对,一定会执行的代码
      alert('弹出对话框')
    }
    console.log(11)
  }
  fn()
</script>

2.3 debugger

debugger 相当于打断点

3 处理this

3.1 this指向

P193:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=193

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

普通函数没有明确调用者时 this 值为 window,严格模式下没有调用者时 this 的值为 undefined

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

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

注意情况1:

在开发中【使用箭头函数前需要考虑函数中 this 的值】,事件回调函数使用箭头函数时,this 为全局的 window

因此DOM事件回调函数如果里面需要DOM对象的this,则不推荐使用箭头函数

注意情况2:

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

3.2 改变this

P194:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=194

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) // windowconsole.log(x +y)
}
// 1.调用函数
// 2. 改变this指向
fn.call(obj, 1, 2)

2. apply()-理解

P195:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=195

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

语法:fun.apply(thisArg, [argsArray])

  • thisArg:在fun函数运行时指定的 this 值
  • argsArray:传递的值,必须包含在数组里面
  • 返回值就是函数的返回值,因为它就是调用函数
  • 因此 apply 主要跟数组有关系,比如使用 Math.max() 求数组的最大值
// 求和函数
function counter(x, y) {
  return x + y
}
// 调用 counter 函数,并传入参数
let result = counter.apply(null, [5, 10])
console.log(result)

3. bind()-重点

P196:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=196

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()

相同点:

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

区别点:

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

主要应用场景:

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

4 性能优化

4.1 防抖

P197:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=197

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

使用场景:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测

4.2 防抖

P198:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=198

节流:单位时间内,频繁触发事件,只执行一次

使用场景:

高频事件:鼠标移动mousemove、页面尺寸缩放resize、滚动条滚动scroll等等

5 综合案例

P199:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=199

6 完结撒花

P200:https://www.bilibili.com/video/BV1Y84y1L7Nn?p=200

::: block-2
感谢这段时间奋斗的自己,\
让我们这段时间变得有价值。
:::


<center>结束</center>

本文由mdnice多平台发布


TigerZ知识宝库
4 声望10 粉丝