思维导图
高阶技巧
1. 深浅拷贝
1.1 浅拷贝
1.2 深拷贝
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div></div> <script> function getTime() { document.querySelector('div').innerHTML = new Date().toLocaleString() setTimeout(getTime, 1000) } getTime() </script> </body> </html>
递归函数实现深拷贝
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> const obj = { uname: 'pink', age: 18, hobby: ['乒乓球', '足球'], family: { baby: '小pink' } } const o = {} // 拷贝函数 function deepCopy(newObj, oldObj) { debugger for (let k in oldObj) { // 处理数组的问题 一定先写数组 在写 对象 不能颠倒 if (oldObj[k] instanceof Array) { newObj[k] = [] // newObj[k] 接收 [] hobby // oldObj[k] ['乒乓球', '足球'] deepCopy(newObj[k], oldObj[k]) } else if (oldObj[k] instanceof Object) { newObj[k] = {} deepCopy(newObj[k], oldObj[k]) } else { // k 属性名 uname age oldObj[k] 属性值 18 // newObj[k] === o.uname 给新对象添加属性 newObj[k] = oldObj[k] } } } deepCopy(o, obj) // 函数调用 两个参数 o 新对象 obj 旧对象 console.log(o) o.age = 20 o.hobby[0] = '篮球' o.family.baby = '老pink' console.log(obj) console.log([1, 23] instanceof Object) // 复习 // const obj = { // uname: 'pink', // age: 18, // hobby: ['乒乓球', '足球'] // } // function deepCopy({ }, oldObj) { // // k 属性名 oldObj[k] 属性值 // for (let k in oldObj) { // // 处理数组的问题 k 变量 // newObj[k] = oldObj[k] // // o.uname = 'pink' // // newObj.k = 'pink' // } // } </script> </body> </html>
lodash实现深拷贝
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 先引用 --> <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) </script> </body> </html>
利用JSON实现深拷贝
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> 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) </script> </body> </html>
2.异常处理
2.1 throw 抛异常
2.2 try/catch 捕获错误信息
2.3 debugger
3.处理this
3.1 this指向
普通函数
箭头函数
3.2 改变this
call()
apply()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> const obj = { age: 18 } function fn(x, y) { console.log(this) // {age: 18} console.log(x + y) } // 1. 调用函数 // 2. 改变this指向 // fn.apply(this指向谁, 数组参数) fn.apply(obj, [1, 2]) // 3. 返回值 本身就是在调用函数,所以返回值就是函数的返回值 // 使用场景: 求数组最大值 // const max = Math.max(1, 2, 3) // console.log(max) const arr = [100, 44, 77] const max = Math.max.apply(Math, arr) const min = Math.min.apply(null, arr) console.log(max, min) // 使用场景: 求数组最大值 console.log(Math.max(...arr)) </script> </body> </html>
bind()-重点
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button>发送短信</button> <script> const obj = { age: 18 } function fn() { console.log(this) } // 1. bind 不会调用函数 // 2. 能改变this指向 // 3. 返回值是个函数, 但是这个函数里面的this是更改过的obj const fun = fn.bind(obj) // console.log(fun) fun() // 需求,有一个按钮,点击里面就禁用,2秒钟之后开启 document.querySelector('button').addEventListener('click', function () { // 禁用按钮 this.disabled = true window.setTimeout(function () { // 在这个普通函数里面,我们要this由原来的window 改为 btn this.disabled = false }.bind(this), 2000) // 这里的this 和 btn 一样 }) </script> </body> </html>
4.性能优化
4.1 防抖
lodash提供的防抖处理
_.debounce(mouseMove, 500)
手写防抖
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .box { width: 500px; height: 500px; background-color: #ccc; color: #fff; text-align: center; font-size: 100px; } </style> </head> <body> <div class="box"></div> <script> const box = document.querySelector('.box') let i = 1 // 让这个变量++ // 鼠标移动函数 function mouseMove() { box.innerHTML = ++i // 如果里面存在大量操作 dom 的情况,可能会卡顿 } // 防抖函数 function debounce(fn, t) { let timeId return function () { // 如果有定时器就清除 if (timeId) clearTimeout(timeId) // 开启定时器 200 timeId = setTimeout(function () { fn() }, t) } } // box.addEventListener('mousemove', mouseMove) box.addEventListener('mousemove', debounce(mouseMove, 200)) </script> </body> </html>
4.2 节流
lodash实现节流
手动实现节流
所以使用timer = null 清空定时器
5.综合案例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="referrer" content="never" /> <title>综合案例</title> <style> * { padding: 0; margin: 0; box-sizing: border-box; } .container { width: 1200px; margin: 0 auto; } .video video { width: 100%; padding: 20px 0; } .elevator { position: fixed; top: 280px; right: 20px; z-index: 999; background: #fff; border: 1px solid #e4e4e4; width: 60px; } .elevator a { display: block; padding: 10px; text-decoration: none; text-align: center; color: #999; } .elevator a.active { color: #1286ff; } .outline { padding-bottom: 300px; } </style> </head> <body> <div class="container"> <div class="header"> <a href="http://pip.itcast.cn"> <img src="https://pip.itcast.cn/img/logo_v3.29b9ba72.png" alt="" /> </a> </div> <div class="video"> <video src="https://v.itheima.net/LapADhV6.mp4" controls></video> </div> <div class="elevator"> <a href="javascript:;" data-ref="video">视频介绍</a> <a href="javascript:;" data-ref="intro">课程简介</a> <a href="javascript:;" data-ref="outline">评论列表</a> </div> </div> <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script> <script> // 1. 获取元素 要对视频进行操作 const video = document.querySelector('video') video.ontimeupdate = _.throttle(() => { // console.log(video.currentTime) 获得当前的视频时间 // 把当前的时间存储到本地存储 localStorage.setItem('currentTime', video.currentTime) }, 1000) // 打开页面触发事件,就从本地存储里面取出记录的时间, 赋值给 video.currentTime video.onloadeddata = () => { // console.log(111) video.currentTime = localStorage.getItem('currentTime') || 0 } </script> </body> </html>