1. 深浅拷贝
const obj = {uname: 'nidie',age: 18}// o对象直接复制obj,直接赋值将obj的地址也给了oconst o = obj// 正常打印18console.log(o);// 对o改动,打印obj,obj也被改动了o.age = 20console.log(o);console.log(obj);
1.1 浅拷贝
拷贝对象:Object.assgin()
拷贝数组:Array.prototype.concat()
const obj = {uname: 'nidie',age: 18}// 浅拷贝const o = { ...obj }console.log(o);// 对未改动的obj没有影响o.age = 20console.log(o)console.log(obj);console.log('----------------------');// 利用assign方法浅拷贝const oo = {}Object.assign(oo, obj)oo.age = 20console.log(oo);console.log(obj);console.log('----------------------');// 但是浅拷贝仍然存在问题const objj = {uname: 'nidie',age: 18,family: {baby: 'son'}}const ooo = {}Object.assign(ooo, objj)// 简单数据类型age直接赋值没关系,obj对象中存储的family地址会给oooooo.age = 20ooo.family.baby = '牛魔'// 只想改变ooo的family对象里面的属性,却把objj的也改了console.log(ooo);console.log(objj);
总结:
1.2 深拷贝
递归实现深拷贝
function getTime() {document.querySelector('div').innerHTML = new Date().toLocaleString()// 每隔一秒调用一次自己setTimeout(getTime, 1000)}getTime()
注意:
- 利用函数递归
- 普通属性直接赋值,遇到复杂数据类型,数组,对象则调用自己
- 数组的逻辑顺序要在对象前面
const obj = {uname: 'nidie',age: 18,hobby: ['lu', 'lulu'],family: {baby: 'babybaby'}}const o = {}// 将obj拷贝给ofunction deepCopy(newObj, oldObj) {// 遍历旧对象for (let k in oldObj) {// if的逻辑顺序不能反,因为数组也属于对象,必须先筛选完数组再写对象// 处理数组的问题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 {// k 属性名 oldObj[k] 属性值// newObj[k] === o.unamenewObj[k] = oldObj[k]}}}deepCopy(o, obj) //o新对象 obj旧对象o.age = 20o.hobby[0] = 'bulu'o.family.baby = '牛魔'console.log(o);console.log(obj);
利用库函数直接深拷贝
<script src="lodash.js"></script><script>const obj = {uname: 'nidie',age: 18,hobby: ['lu', 'lulu'],family: {baby: 'babybaby'}}const o = _.cloneDeep(obj)console.log(o);
利用JSON实现深拷贝
const obj = {uname: 'nidie',age: 18,hobby: ['lu', 'lulu'],family: {baby: 'babybaby'}}// 把对象转换为JSON字符串console.log(JSON.stringify(obj));// parse方法再将字符串转换为对象const o = JSON.parse(JSON.stringify(obj))console.log(o);o.family.baby = '牛魔'console.log(o)console.log(obj);;
总结
2. 异常处理
2.1 throw抛异常
function fn(x, y) {if (!x || !y) {// throw '你没传参'// 抛出异常并终止程序throw new Error('没传参')}return x + y}console.log(fn());
总结
2.2 try/catch捕获异常
<body><p>123</p><script>function fn() {try {const p = document.querySelector('.p')p.style.color = 'red'}catch (err) {console.log(err.message);// 配合throw使用throw new Error('错了吧人才')return}finally {// 不管程序是否正确,一定会执行finnalyalert('你好')}// catch会拦截错误,但是不会中断程序执行 加入return中断程序}fn()</script>
</body>
总结
2.3 debugger
3. 处理this
3.1 this指向-普通函数
对于普通函数来说,谁调用,this就指向谁
总结
3.2 this指向-箭头函数
箭头函数this一层层往上找,找到最近的对象
3.2 改变this
call
apply
const obj = {age: 18}function fn(x, y) {console.log(this);console.log(x + y);return x + y}// 调用函数,并且让fn中的this指向了第一个参数obj// apply第二个参数必须放数组fn.apply(obj, [1, 2])// 本身就是在调用函数,所以返回值就是函数的返回值console.log(fn.apply(obj, [1, 2]));
bind
与call()
和apply()
不同的是,bind不会立即调用函数
const obj = {age: 18}function fn() {console.log(this);}// bind不会调用函数// 可以改变this指向// 返回值是一个更改过this的函数const fun = fn.bind(obj)fun()// 需求:有一个按钮,点击里面就禁用,2秒钟后开启const btn = document.querySelector('button')btn.addEventListener('click', function () {// 禁用按钮this.disabled = true###setTimeout(function () {// 在普通函数中的话,要将this指向的window改为btnthis.disabled = false}.bind(this), 2000);})
总结
4. 性能优化
4.1 防抖(debounce)
<script src="lodash.js"></script><script>// 鼠标在盒子中滑动,数字显示+1const box = document.querySelector('.box')let i = 1function mouseMove() {// 存在大量消耗性能的代码,dom操作、数据处理,可能造成卡顿box.innerHTML = i++}// box.addEventListener('mousemove', mouseMove)// 利用库函数lodash防抖函数// _.debounce(fun,时间)box.addEventListener('mousemove', _.debounce(mouseMove, 500))</script>
// 手写防抖函数// 利用setTimeout定时器实现// 1. 声明定时器变量// 2. 每次鼠标移动的时候都要先判断是否有定时器,如果有的话先清除以前的// 3. 如果没有定时器,就开启定时器,存入到定时器变量中// 4. 定时器里面写函数调用function debounce(fn, t) {let timer// return 返回一个匿名函数return function () {if (timer) clearInterval(timer)timer = setTimeout(function () {fn()}, t)}}box.addEventListener('mousemove', debounce(mouseMove, 100))
4.2 节流
// 利用节流实现性能优化// 鼠标在盒子中滑动,数字显示+1const box = document.querySelector('.box')let i = 1function mouseMove() {// 存在大量消耗性能的代码,dom操作、数据处理,可能造成卡顿box.innerHTML = i++}// 利用lodash库实现节流,500ms之后采取一次+1// 语法:_.throttle('mousemove'),_.throttle(mouseMove,500)box.addEventListener('mousemove', _.throttle(mouseMove, 3000))