一、浅拷贝
拷贝:浅拷贝和深拷贝:只针对引用数据类型
浅拷贝:拷贝的是地址
常见方法:
1.拷贝对象:
Object.assign(新的空的对象,老的有值的对象):Object.assign(o,obj)
展开运算符:var o = {...obj}
2.拷贝数组:
展开运算符:var arr1=[...arr]
var arr1=[].concat(arr)
<script>
var obj={
name:'王多磊',
age:['18','28','38'],
sex:'不祥'
}
// var obj1=obj
// 引用数据类型复制给其他变量时,只是指向堆的url地址复制了一份,只要值改变,其他的变量里面的值也会跟着改变
// console.log(obj)
// console.log(obj1)
// 拷贝 浅拷贝 1 Object.assign浅拷贝 只能拷贝第一层的基本数据类型 2 扩展运算符 浅拷贝
// var o={}
// Object.assign(o,obj)
// obj.name='麻子'
// obj.age[0]='40'
// obj.sex='男'
// console.log(o)
// var o={...obj}
// obj.name='郑日安'
// console.log(o)
// 数组浅拷贝 1 concat实现浅拷贝 2 扩展运算符实现浅拷贝
var arr=['12','王多磊',{name:'小磊磊'}]
// concat
// var arr1=[].concat(arr)
// arr.name='老王'
// arr.age='28'
// arr[2].name='小邓'
// console.log(arr1)//12 王多磊 小邓
var arr1=[...arr]
arr[1]='老王'
arr[0]='28'
arr[2].name='小邓'
console.log(arr1)//12 王多磊 小邓
console.log(arr)//28 老王 小邓
</script>
二、函数递归
函数递归:函数内部自己调用自己
作用:类似循环
注意:栈溢出 加return
递归案例:输入id号可以返回对应的数据对象
<script>
// 输入id号可以返回对应的数据对象
var arr = [{
id: 1,
uname: '电脑',
groups: [
{
id: 2,
uname: '键盘',
groups: [
{
id: 3,
uname: '鼠标'
},
{
id: 4,
uname: '散热器'
},
]
},
{
id: 5,
uname: '电脑包'
}
]
},
{
id: 6,
uname: '电脑支架'
}
];
// var arr1=[{},{}]
function getID(arrs,id){
var obj={}
arrs.forEach(function(item){
// console.log(item) // item拿到的是arr数组的外层两个元素(id是1的时候)
if(item.id==id){
obj=item
}
else if(item.groups&&item.groups.length>0){
// 想要里层数据可以使用递归函数拿到,数据里面应该有groups并且长度需要大于0
obj = getID(item.groups,id)
}
// 只要有groups这个属性,就还有一层嵌套
});
return obj
}
// console.log(getID(arr,1))
// console.log(getID(arr,2))
console.log(getID(arr,4))
// var tree =getID(arr,4)
</script>
三、深拷贝
深拷贝:拷贝的是对象,不是地址
常见方法:
1.通过递归实现深拷贝
2.lodash/cloneDeep
3.通过JSON.stringify()实现
深拷贝实现:
1.深拷贝出来的新对象不会影响老对象,用到函数递归
2.普通拷贝直接赋值,遇到数组再次调用递归函数
3.遇到对象再次调用递归函数解决
先Array,再对象
var obj = {
uname:'pink',
age:18,
habby:['乒乓球','足球'],
family:{
baby:'小pink'
}
}
var o = { }
//拷贝函数
function deepCopy(newObj,oldObj){
for(var k in oldObj){
//处理数组问题 一定先写数组 再写对象 不能颠倒
if(oldObj[k] instanceof Array){
newObj[k] = []
//newObj[k]接收[] habby
//oldObj[k] ['乒乓球','足球']
deepCopy(newObj[k],oldObj[k])
}
else if(oldObj[k] instanceof Object){
newObj[k] = {}
//newObj[k]接收[] habby
//oldObj[k] ['乒乓球','足球']
deepCopy(newObj[k],oldObj[k])
}
else {
//k 属性名 uname oldObj[k] 属性值 18
// newObj[k]//newObj[k]===o.k
// newObj[k] === o.uname
newObj[k] = oldObj[k]//把老的值赋给新的属性
}
}
}
deepCopy(o,obj)//函数调用 两个参数 o 新对象 obj 旧对象
console.log(o);//{uname: 'pink', age: 18}
o.age=20
o.habby[0]='篮球'
o.family.baby = '老pink'
console.log(obj);//{uname: 'pink', age: 18}
<script>
// 想把整个obj全部拷贝出来,可以使用递归进行拷贝
var obj = {
id: 1,
name: '李四',
color: ['blue', 'red'],
msg: {
age: 20
}
}
function cloneDeep(copyObj) {
// 创建一个变量,因为不确定数据类型,所有先不赋值
var obj
if(Array.isArray(copyObj)){
// 如果copyObj是数据,那就给obj赋值为空数组
obj=[]
// 通过数组的遍历进行拷贝
// 由于数组的元素可以是任意值,所以需要对内部进行判断数据类型
// obj[i]=cloneDeep(copyObj[i])通过这个方法进行回调,完成数据类型的判断
for(var i=0;i<copyObj.length;i++){
obj[i]=cloneDeep(copyObj[i])
}
// 通过回电函数完成拷贝,返回obj
return obj
}else if (copyObj instanceof Object){
// 给obj一个空对象
obj={}
for(var k in copyObj){
obj[k]=cloneDeep(copyObj[k])
}
return obj
}else{
return copyObj
}
}
var newObj=cloneDeep(obj)
obj.msg.age=50
console.log(obj)
console.log(newObj)
</script>
<script>
// 想把整个obj全部拷贝出来,可以使用递归进行拷贝
var obj = {
id: 1,
name: '李四',
color: ['blue', 'red'],
msg: {
age: 20
}
}
var newObj=_.cloneDeep(obj)
obj.msg.age=50
console.log(obj)
console.log(newObj)
</script>
四、防抖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="lodash.min.js"></script>
<style>
div{
width: 200px;
height: 200px;
background-color:skyblue;
margin: 0 auto;
line-height: 200px;
text-align: center;
font-size: 24px;
}
</style>
</head>
<body>
<div>1</div>
<script>
console.log(_)
// 防抖:在单位时间内,频繁触发事件,只执行最后一次, (例如:1秒内,只要有新的触发事件产生,就从0开始计时)
// 用户输入input、手机号验证、密码验证、邮箱验证
// 鼠标移动就自加一
var div=document.querySelector('div')
var num=1
function fn(){
div.innerHTML=num++
}
// fun 要放抖动的函数
// wait 是延迟的时间
div.addEventListener('mousemove', _.debounce(fn,1000))
</script>
</body>
</html>
五、手写防抖
<body>
请输入内容:<input type="text">
<script>
// 声明一个定时器变量用于存储定时器
// 当输入内容时(当事件触发时),都先判断一下有没有定时器,有的话就先清除之前的定时器
// 没有定时器的话,就向下执行,把定时器赋值给timer
// 开始执行定时器里的内容
var input=document.querySelector('input')
var timer
input.addEventListener('input',function(){
if(timer) clearTimeout(timer)
timer= setTimeout(function(){
console.log(input.value)
},3000)
})
</script>
</body>
六、节流
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="lodash.min.js"></script>
<style>
div{
width: 200px;
height: 200px;
background-color: skyblue;
margin: 0 auto;
}
</style>
</head>
<body>
<div></div>
<script>
/*
防抖节流的区别:防抖是只要在规定时间内重复触发不停止的情况下,就不会执行代码
节流是只要你在重复触发不停止的情况下,在规定时间执行完后就会执行下一次
*/
// 节流:在规定时间内,频繁触发事件,只执行一次
// 例如:1秒内,只要有新的触发事件产生,无效,除非之前的触发事件执行完毕
// 场景:scroll 页面尺寸缩小
var div=document.querySelector('div')
var num=1
function fn(){
div.innerHTML=num++
}
div.addEventListener('mousemove',_.throttle(fn,1000))
</script>
</body>
</html>
七、手写节流
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
height: 3000px;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
var timer;
document.addEventListener('scroll',function(){
console.log(window.pageYOffset)
if(window.pageYOffset>200){
if(!timer){
timer = setTimeout(function(){
console.log('我被卷上去了')
timer=null
// 在setTimeout定时器里面无法清除定时器,因为定时器还在执行,所以需要用timer=null手动置空定时器
// clearTimeout(timer)
},3000)
}
}
})
</script>
</body>
</html>
八、清除定时器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
height: 3000px;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
var timer;
timer=setTimeout(function(){
// clearTimeout(timer)
timer=null
console.log(timer)
},1000)
</script>
</body>
</html>