1. 深浅拷贝
const obj = {
uname: 'nidie',
age: 18
}
// o对象直接复制obj,直接赋值将obj的地址也给了o
const o = obj
// 正常打印18
console.log(o);
// 对o改动,打印obj,obj也被改动了
o.age = 20
console.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 = 20
console.log(o)
console.log(obj);
console.log('----------------------');
// 利用assign方法浅拷贝
const oo = {}
Object.assign(oo, obj)
oo.age = 20
console.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地址会给ooo
ooo.age = 20
ooo.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拷贝给o
function 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.uname
newObj[k] = oldObj[k]
}
}
}
deepCopy(o, obj) //o新对象 obj旧对象
o.age = 20
o.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 {
// 不管程序是否正确,一定会执行finnaly
alert('你好')
}
// 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改为btn
this.disabled = false
}.bind(this), 2000);
})
总结
4. 性能优化
4.1 防抖(debounce)
<script src="lodash.js"></script>
<script>
// 鼠标在盒子中滑动,数字显示+1
const box = document.querySelector('.box')
let i = 1
function 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 节流
// 利用节流实现性能优化
// 鼠标在盒子中滑动,数字显示+1
const box = document.querySelector('.box')
let i = 1
function mouseMove() {
// 存在大量消耗性能的代码,dom操作、数据处理,可能造成卡顿
box.innerHTML = i++
}
// 利用lodash库实现节流,500ms之后采取一次+1
// 语法:_.throttle('mousemove'),_.throttle(mouseMove,500)
box.addEventListener('mousemove', _.throttle(mouseMove, 3000))