JS学习笔记16
深浅拷贝(针对引用类型)
浅拷贝
拷贝的是地址
常见方法:
- 拷贝对象:Object.assgin() / 展开运算符 {…obj} 拷贝对象
- 拷贝数组:Array.prototype.concat() 或者 […arr]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const obj = { uname: 'jason', age: 18, family: { baby: '1' } } const o = {} Object.assign(o, obj) o.age = 20 o.family.baby = '2' console.log(o) console.log(obj)
|
如果是简单数据类型拷贝值,引用数据类型拷贝的是地址 (简单理解: 如果是单层对象,没问题,如果有多层就有问题)
深拷贝
拷贝的是对象,不是地址
==通过递归实现深拷贝==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const obj={ uname: 'jason', age: 18, hobby: ['1','2'] } const o={} function deepcopy(newobj,oldobj){ for(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] } } }
|
Lodash
js库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <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>
|
利用JSON实现深拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <body> <script> const obj = { uname: 'pink', age: 18, hobby: ['乒乓球', '足球'], family: { baby: '小pink' } } const o = JSON.parse(JSON.stringify(obj)) console.log(o) o.family.baby = '123' console.log(obj) </script> </body>
|
先转换成字符串,再转成对象。
异常处理
throw抛异常
1 2 3 4 5 6 7 8 9 10 11
| <script> function fn(x, y) { if (!x || !y) { throw new Error('没有参数传递过来') }
return x + y } console.log(fn()) </script>
|
捕获异常 try catch finally
通过try/catch捕捉错误信息(浏览器提供的错误信息)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script> function fn() { try { const p = document.querySelector('.p') p.style.color = 'red' } catch (err) { console.log(err.message) throw new Error('你看看,选择器错误了吧') } finally { alert('弹出对话框') } console.log(11) } fn() </script>
|
dubugger
相当于断点,直接在代码里面插入
this
this指向
普通函数
谁调用指向谁
普通函数没有明确调用者时this值为window,严格模式下没有调用者为undefined
箭头函数
- 箭头函数会默认帮我们绑定外层this的值 ,箭头函数中this的值和外层的this是一样的
- 箭头函数中this引用的就是最近作用域中的this
- 向外层作用域中,一层层查找this,直到有this的定义
箭头函数中访问的 this
不过是箭头函数所在作用域的 this
变量。
原型,构造函数,dom事件函数等等不方便使用箭头函数
适用需要使用上层this的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <script> console.log(this) const sayHi = function() { console.log(this) } const user = { name: '小明', walk: () => { console.log(this) }, sleep: function () { let str = 'hello' console.log(this) let fn = () => { console.log(str) console.log(this) } fn(); } }
user.sayHi = sayHi user.sayHi() user.sleep() user.walk() </script>
|
改变this
call()
使用call方法调用函数,同时指定被调用函数中this的值
1
| fun.call(thisArg,arg1,arg2,...)
|
- thisArg 在fun运行时指定this的值
- arg1,arg2函数正常的形参
apply()
使用apply方法调用函数,同时指定被调用函数中this的值
1
| fun.apply(thisArg,[argsArray])
|
argsArray:传递的值,必须包含在数组里面
1 2 3 4 5 6 7
| const obj = { age: 18 } function fn(x, y) { console.log(this) console.log(x + y) }
|
返回值就是函数的返回值
==bind()==
不会调用函数,能改变函数内部this指向,返回值是一个新的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <script> function sayHi() { console.log(this) } let user = { name: '小明', age: 18 } let sayHello = sayHi.bind(user); sayHello() </script>
|
防抖
场景:搜索框搜索输入。只需用户最后依次输入完成
手机号,邮箱验证输入检测
实现:
- lodash提供的防抖处理
1
| _.debounce(func,[wait=0],[options=])
|
2.手写一个防抖函数
(防抖的核心就是利用setTimeout实现)
- 声明定时器变量
- 每次鼠标移动时要先判断是否有定时器,有的话清除以前的定时器
- 如果没有定时器,则开启
- 定时器里面写函数调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function mouseMove() { box.innerHTML = ++i } function debounce(fn,t){ let timeId return function(){ if(timeId) clearTimeout(timeId) timeId =setTimeout(function(){ fn(); },t) } } box.addEventListener('mousemove',debounce(mouseMove,500))
|
为什么return一个匿名函数?不用行不行?
确保事件触发的是匿名函数,不会重新将timer置为null。同时,匿名函数是一个闭包,timer变量不会被回收。这样,就能使用clearTimeout
清空上次的定时器了。默默摸摸你
节流 throttle
单位时间内,频繁触发事件,只执行一次
- lodash提供的节流函数
1
| box.addEventListener('mousemove', _.throttle(mouseMove, 500))
|
2.手写节流函数
1 2 3 4 5 6 7 8 9 10 11
| function throttle(fn,t){ let timer=null return function(){ if(!timer){ timer=setTimeout(function(){ fn() timer=null },t) } } }
|