JS进阶 4——深浅拷贝、异常处理、节流防抖
1.深浅拷贝
- 直接复制对象的问题
const obj = {uname: 'xiao',age: '18'}const o = objo.age = 20console.log(o)
//原来对象的age也被彻底改变了console.log(obj)
-
浅拷贝——内部引用仍然拷贝的是地址
- 拷贝对象:Object.assdin()或{…obj}
- 拷贝数组:Array.prototype.concat()或{…arr}
//拷贝对象 const obj = {uname: 'xiao',age: '18'}//第一种方法const o1 = { ...obj }//第二种方法const o2 = {}Object.assign(o, obj)
- 问题:只能拷贝最外层,只能防止最外层的属性复制后被更改:
const obj = {uname: 'xiao',age: '18',family: {baby: '小小怪'}} const o = { ...obj }o.age = 20o.family.baby = '大大怪'console.log(o)console.log(obj)//obj中的family中的baby被改变了
-
深拷贝——拷贝对象
-
通过递归实现深拷贝
const obj = {uname: 'pink',age: 18,hobby: ['兵乓球', '足球'],family: {baby: '小小怪'}}const o = {}//拷贝function deepCopy(newObj, oldObj) {//k:属性名 不能使用newObj.kfor (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]}}deepCopy()}deepCopy(o, obj)console.log(o)
-
JS库lodash里面cloneDeep()
<!-- 先引用 --><script src="./lodash.min.js"></script><script>const obj = {uname: 'pink',age: 18,hobby: ['兵乓球', '足球'],family: {baby: '小小怪'}}const o = _.cloneDeep(obj)console.log(o)o.family.baby = '大大怪'console.log(obj)
-
通过JSON.stringify(实现)
const obj = {uname: 'pink',age: 18,hobby: ['兵乓球', '足球'],family: {baby: '小小怪'}}//将对象转换为JSON字符串// JSON.stringify(obj)//将字符串转化为对象// JSON.parse(JSON.stringify(obj))//先转化为字符串,在转换为对象,是一个新的对象不指向原来的对象const o = JSON.parse(JSON.stringify(obj))console.log(o)o.family.baby = '123'console.log(obj)
-
2.异常处理
-
throw抛异常
-
异常处理指提前预估代码执行中可能出现的错误,然后最大程度的避免错误的发生
function counter(x, y) {if (!x || !y) {throw new Error('参数不能为空!')//发生异常程序会中断,抛出异常}return x + y}counter()
- throw抛出异常信息,程序会终止执行
- throw后面跟的是错误提示信息
- Error对象配合throw使用,能够设置更详细的错误信息
-
-
try/catch捕获异常
function fn() {try {//可能错误的代码const p = document.querySelector('.p')p.style.color = 'red'} catch (err) {//拦截错误,提示浏览器提供的错误信息,不中断程序的执行console.log(err.message)//配合throw使用throw new Error('选择器错啦~')//加return 中断程序// return}finally {//无论程序对不对,都要执行的代码alert('弹出对话框')}}fn()
- 用于捕获错误信息
- 将预估可能发生错误的代码写在try代码段中
- try代码段出现错误,会执行catch代码段
- finally不管是否有错误都会执行
-
debugger:设置断点,调试代码
3.this指向
-
普通函数this指向:谁调用指向谁
-
箭头函数:本身没有this,是最近一级的this指向
-
注意事项:
- 如果要使用this,就不要使用箭头函数
- 构造函数、原型函数、DOM事件函数不适用箭头函数
-
改变this
-
call():调用函数,并指定被调函数中this的值
- 函数名.call(thisArg,参数1,参数2…)
const obj = {uname: '小小怪'}function fn(x, y) {console.log(this)console.log(x + y)}//第一个值指向this的指向,后面的参数是传递的参数fn.call(obj, 1, 2) // obj,3
-
apply():调用函数,同时指定被调函数中this的值,第二个参数为数组
- 函数名.apply(thisArg,[argsArray])
const obj = {uname: '小小怪'}function fn(x, y) {console.log(this)console.log(x + y)}//第一个值指向this的指向,后面的参数是传递的参数fn.apply(obj, [1, 2]) // obj,3
-
bind():不会调用函数,只改变this指向
- 函数名.bind(thisArg,参数1,参数2…)
- 使用场景
//按钮点击后禁用,两秒开启const btn = document.querySelector('button')btn.addEventListener('click', function () {this.disabled = truewindow.setTimeout(function () {this.disabled = false}.bind(btn), 2000)})
-
4.防抖debounce
-
防抖:单位之间内,频繁触发事件,只执行最后一次(王者荣耀回城)
-
实现方式:
- lodash库提供的防抖
- _debounce(func,[wait=0],[option=]):延迟wait值后调用func函数
<div class="box"></div><script src="./lodash.min.js"></script><script>const box = document.querySelector('.box')let i = 1function mouseMove() {box.innerHTML = i++}//500毫秒之后采取+1box.addEventListener('mousemove', _.debounce(mouseMove, 500))</script>
- 手写一个防抖函数来处理——setTimeout
const box = document.querySelector('.box')let i = 1function mouseMove() {box.innerHTML = i++}function debounce(fn, t) {let timerreturn function () {if (timer) clearTimeout(timer)timer = setTimeout(function () {fn()}, t)}}//500毫秒之后采取+1box.addEventListener('mousemove', _.debounce(mouseMove, 500))
- lodash库提供的防抖
5.节流-throttle
-
节流:单位时间内,频繁触发事件,只执行一次(王者荣耀技能冷却)
-
实现方式
-
lodash提供的节流函数来处理
const box = document.querySelector('.box')let i = 1function mouseMove() {box.innerHTML = i++}//500毫秒之后采取+1box.addEventListener('mousemove', _.throttle(mouseMove, 3000))
-
手写一个节流函数来处理
const box = document.querySelector('.box')let i = 1function mouseMove() {box.innerHTML = i++}function throttle(fn, t) {let timer = nullreturn function () {if (!timer) {timer = setTimeout(function () {fn()timer = null}, t)}}}//500毫秒之后采取+1box.addEventListener('mousemove',_.throttle(mouseMove, 3000))
-