深拷贝和浅拷贝
深拷贝和浅拷贝
一、浅拷贝
概述:
只拷贝第一层的值,其他后面拷贝的是地址。
示例:
使用u盘在一台电脑上拷贝文件,使用浅拷贝拷贝的相当于快捷方式。
第一层俩个内容不一样,其他每层都是指向同一个文件
1、实现浅拷贝的方法
(1)Object.assign (实现浅拷贝)
let obj = {
user:{
name:
"
jack"
}
}
//assign实现浅拷贝
let copyObj = Object.assign({},obj)
copyObj.user.name = 'tom'
console.log(obj.user.name);
console.log(copyObj.user == obj.user);//true
(2)Array.prototype.concat
let arr = [
{name:'jack'}
]
//利用concat方法实现对应的浅拷贝
let copyArr = arr.concat()
console.log(arr[0] == copyArr[0]);
console.log(copyArr == arr); //false
(3)Array.prototype.slice
//slice 截取方法
let sliceArr = arr.slice(0)
console.log(arr[0] == sliceArr[0]);
console.log(sliceArr == arr); //false
(4)...扩展运算符实现
//开辟一个新的变量
let newArr = [...arr]
console.log(newArr[0] == arr[0]);
console.log(newArr == arr); //false
(5)使用第三方的插件 lodash.js _.clone方法实现
//实现浅拷贝
let obj1 = {
user:{
name:
"
jack"
}
}
let copyObj1 = _.clone(obj1)
console.log(copyObj1.user == obj1.user);//true
console.log(copyObj1 == obj1);//false
二、深拷贝
概述:
每层都进行值拷贝
示例:
使用u盘在一台电脑上拷贝文件,将文件所有复制一份,在粘贴一份。这俩份文件除了值是一致的,其他都不一样。俩者的地址是独立的。
1、实现方式
(1)使用字符串转换(序列化 JSON.stringify 和反序列化 JSON.parse)
let obj = {
users:[{
name:
'
jack'
}]
}
//每层都只拷贝值 每层的地址都不一样
// 字符串转换 序列化和反序列化
let copyObj = JSON.parse(JSON.stringify(obj))
console.log(copyObj == obj); //false
console.log(copyObj.users == obj.users); //false
console.log(copyObj.users[0] == obj.users[0]); //false
console.log(copyObj.users[0].name == obj.users[0].name); //true
(2)使用lodash 里面_.cloneDeep
//使用第三方lodash _.cloneDeep方法实现
let cloneObj = _.cloneDeep(obj)
console.log(cloneObj == obj); //false
console.log(cloneObj.users == obj.users); //false
console.log(cloneObj.users[0] == obj.users[0]); //false
console.log(cloneObj.users[0].name == obj.users[0].name); //true
(3)使用递归实现对应的深拷贝(面试题)
思路
- 根据传入的对象 进行判断 如果不是对象直接赋值
- 如果是对象就要先创建一个对象 那么就需要判断是数组还是对象 如果是数组创建数组 如果是对象就创建对象
- 如果是数组获或者是对象 取出里面的值进行递归赋值
function deepClone(target) {
//如果传入的目标对象是空就直接返回
if (!target) return {}
let copyObj = {} //接收拷贝好的对象
//根据typeOf的返回值进行判断 判断是否为对象
if (typeof target == 'object') {
//判断是否为数组
copyObj = target instanceof Array ? [] : {}
//遍历所有的key加入到对应的copyObj里面
for (let key in target) {
//将对应的值和key加入到对应的copyObj里面
copyObj[key] = deepClone(target[key])
}
} else {
copyObj = target //直接赋值
}
return copyObj
}
三、Vue底层代码梳理
1、虚拟dom(是一个对象)
虚拟dom替代了dom节点,减少了对实际dom操作。(重绘和回流)。根据虚拟dom生成对应的实体dom
2、diff 算法 (用于比对的算法)
一个页面其中一个内容发送变化,按理来说应该只改这一个部分的渲染内容,而不应该进行整体渲染。那么你需要知道其中一个发送了变化,才能完成相关的操作。diff算法就用来比对出发生变化的部分。在虚拟dom里面进行比对。核心就是在虚拟dom里面进行比对对应的变化,从控制变化内容的渲染。
3、数据驱动(mvvm model 数据 view 视图 viewModel 视图模型用控制对应的视图和数据的交互)
通过改变的对应的数据,来改变对应的视图。双向绑定 从改视图从而改变对应的数据。viewModel完成这个一系列的操作。这个vm对象其实就是我们的vue对象。
4、vue怎么完成对应的视图和数据的交互
- vue2使用了Object.defineProperty和观察者模式来实现的。
- vue3使用proxy来实现的。
5、diff算法的比对流程
(1)利用了pacth,来打补丁包。他去对应比对节点对于发生变化的节点打补丁包。vue对这些补丁的地方会进行重新渲染。
(2)他先比较的是key ,对于没有key的内容 先比较元素节点,再比较文本节点。比较完就会进行打补丁包(抽象的虚拟dom对象),对于这个补丁包他会将他合并到对于的虚拟dom上,再进行渲染。
6、简易版vue
- 主要利用的object.defineProperty进行对应的数据劫持操作
- 提取对应的dom中的命令及相关的内容形成新的dom对象进行相关操作
- 通过对于数据的劫持控制对应的内容发生变化(重新渲染)
(1)v-click 处理点击事件 里面填入对应的vue里面methods里面方法 (原生vue不存在 原生vue中 v-on:click)
(2)v-for 循环渲染对应的数据 里面填入data里面的数组或者对象 (里面的值为 (value,key) in 数组)
<!--item表示对应的值 key表示对应的下标-->
<p class="a" v-for="(item,key) in options">{{item}}</p>
<!--如果不需要对应的key那么可以省略key-->
<p class="a" v-for="item in options">{{item}}</p>
(3)v-model 双向绑定操作 用于表单元素 里面填入data里面的数据
(4)v-html 将对应的data里面的数值渲染到对应的标签内(innerHTML)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name=
"
viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<div>
<button class="a" v-for="(item,key) in options" v-
click="getIndex(key)">{{item}}</button>
</div>
<!-- 数值1 -->
<input type="text" v-model="number1">
<span v-html="ys"></span>
<!-- 数值2 -->
<input type="text" v-model="number2"> =
<button v-click="computed">计算</button>
<!-- 结果 -->
<input type="text" v-model="result">
</div>
<script src="./my_vue.js"></script>
<script>
new Vue({
el: '#app', //挂载点
data: {
number1: '',
number2: '',
result: '',
options: ['+', '-', "*", '/'],
ys:
'
+
'
},
methods: {
computed() {
switch (this.ys) {
case
'
+
'
:
this.result = Number(this.number1) +
Number(this.number2)
break
case
'
-
'
:
this.result = Number(this.number1) -
Number(this.number2)
break
case
'
*'
:
this.result = Number(this.number1) *
Number(this.number2)
break
case
'
/
'
:
this.result = Number(this.number1) /
Number(this.number2)
break
}
},
getIndex(index) {
this.ys = this.options[index]
}
},
})
</script>
</body>
</html>
主要封装这个小型vue是为了理解vue的思想,及相关的原理.(通过虚拟dom进行diff算法比对从而控制对应的渲染)。虚拟dom在内存中进行比对。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· Qt个人项目总结 —— MySQL数据库查询与断言