深浅拷贝只针对引用类型
(1)拷贝对象:Object.assign() / 展开运算符 {...obj}
(2)拷贝数组:Array.prototype.concat() 或者 [...arr]
① 简单数据类型拷贝的是值,引用数据类型拷贝的是地址
② 赋值的时候不会影响原来的值,如果是简单数据类型拷贝值,引用数据类型拷贝的是地址
③ 如果是单层对象,就没问题,如果是多层对象就有问题
改变o 的值不会影响obj的值
如果是多层对象,改变o的值就会影响到obj的值
① 直接赋值,只要是对象,就会互相影响,因为会直接拷贝对象栈里面的地址
② 浅拷贝如果是一层对象,不会相互影响,如果是多层对象,还是会互相影响
① 拷贝对象后,里面的属性值是简单数据类型直接拷贝值
② 如果属性值是引用数据类型则拷贝的是地址
① 通过递归实现深拷贝
② loadash/cloneDeep
③ 通过JSON.stringify()实现
① 函数递归:如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
② 就是自己调自己
③ 递归容易发生“栈溢出"错误,所以必须要加退出条件return
let i = 1
function fn () {
console.log(`这是第${i}次`)
if (i >= 6) {
return
}
i++
fn()
}
fn()
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] = []
deepCopy(newObj[k], oldObj[k])
} else if (oldObj[k] instanceof Object) {
newObj[k] = {}
deepCopy(newObj[k], oldObj[k])
} else {
newObj[k] = oldObj[k]
}
// k 属性名 属性值 oldObj[k]
}
}
deepCopy(o, obj)
o.age = 20
o.hobby[0] = '篮球'
o.family.baby = '小hi'
console.log(o)
console.log(obj)
const obj = {
uname :'pink',
age: 18,
hobby:['乒乓球', '足球'],
family: {
baby: '小pink'
}
}
// 1.先转换为字符串,然后再转回对象,就会生成一个新的对象,跟原来的对象没有关系,
// 修改里面的值不会影响原来的数据
const o = JSON.parse(JSON.stringify(obj))
console.log(o)
o.family.baby = '123'
console.log(obj)
① 异常处理是指预估代码在执行过程中可能发生的错误,然后最大程度的避免错误的发生导致整个程序无法继续执行
function fn(x, y) {
if (!x || !y) {
// throw '没有参数传递进来'
// 精确到行
throw new Error('没有参数传递进来')
}
return x + y
}
① 代码示例
function fn(){
try {
const p = document.querySelector('.p')
p.style.color = 'red'
} catch (err) {
// 只是拦截错误,提示浏览器提供的错误信息,但是不中断程序的执行
console.log(err.message)
// 加return 中断程序
// return
throw new Error('选择器错误了')
}
// 不管程序对不对,一定会执行的代码
finally {
alert('弹出对话框')
}
//
console.log(111)
}
fn()
② 说明
作用:断点调试
const obj = {
uname: 'pink'
}
function fn (x, y) {
console.log(x + y)
console.log(this) // obj
}
// 1.调用函数
// 2.改变this指向
fn.call(obj, 1, 2)
const obj = {
uname: 'pink'
}
function fn (x, y) {
console.log(this)
console.log(x + y)
}
// 1.调用函数 2.改变this指向 3.第三个参数要放一个数组
fn.apply(obj, [1, 2])
求数组最大值
const arr = [2, 4, 5]
const max = Math.max.apply(Math, arr)
console.log(max)
console.log(Math.max(...arr))
const obj = {
uname: 'pink'
}
function fn () {
console.log(this)
}
// 返回值是个函数,但是这个函数里面的this是更改过的obj
const fun = fn.bind(obj)
// console.log(fun)
fun()
① 搜索框搜索输入,只需用户最后一次输入完,再发送请求
② 手机号,邮箱验证输入检测
① losash 提供的防抖来处理
const box = document.querySelector('.box')
let i = 1
function mouseMove() {
box.innerHTML = i++
// 如果里面存在大量消耗性能的代码,比如dom操作,数据处理,可能造成卡顿
}
box.addEventListener('mousemove', _.debounce(mouseMove, 500))
② 手写一个防抖函数来处理
(1)定时器变量
(2)先判断是否有定时器,如果有定时器,先清除以前的定时器
(3)如果没有定时器则开启定时器,记得存到变量里面
(4)在定时器里面调用要执行的函数
function debounce (fn, t) {
let timer
// return 返回一个匿名函数
return function () {
if (timer) clearTimeout(timer)
timer = setTimeout(function () {
fn() // 加小括号调用
}, t)
}
}
box.addEventListener('mousemove', debounce(mouseMove, 500))
① 使用lodash实现
const box = document.querySelector('.box')
let i = 1
function mouseMove() {
box.innerHTML = i++
}
// // 500毫秒之内只会执行一次
box.addEventListener('mousemove', _.throttle(mouseMove, 500))
② 自己写一个节流函数
// 1.声明一个定时器变量
// 2.当鼠标每次滑动都先判断是否有定时器,如果有定时器就不开启
// 3.如果没有定时器则开启定时器
// 4.定时器里面调用要执行的函数
// 5.定时器里面要把定时器清空
function throttle(fn, t) {
let timer = null
return function() {
if (!timer) {
timer = setTimeout(function() {
fn()
// 清空定时器
// 不能使用clearTimeout(timer), 在setTimeout中无法使用clearTimeout来清除定时器
timer = null
}, t)
}
}
}
box.addEventListener('mousemove', throttle(mouseMove, 500))
节流防抖总结