JavaScript高级 —— 学习(四)
目录
一、深浅拷贝
(一)浅拷贝
1.浅拷贝的简单使用
拷贝对象:
拷贝数组:
使用两种浅拷贝方法
2.浅拷贝的问题
(二)深拷贝
1.通过递归实现深拷贝
递归函数:
递归实现过程:
其他问题:
2.利用 lodash 实现深拷贝
3.利用 JSON 实现深拷贝
练习:利用递归函数实现 setTimeout 模拟 setInterval 效果
未完待续。。。。
一、深浅拷贝
结构相同对象,复制对象重新赋值
不能用直接赋值来拷贝对象:o = obj
这样他俩指向同一个地址一个变了,就都变了
深浅拷贝只针对引用数据类型
(一)浅拷贝
适用于单层的对象和数组,不适用于多层嵌套的数组对象拷贝
最外层拷贝数值,内层拷贝地址
1.浅拷贝的简单使用
拷贝对象:
Object.assign() / 展开运算符 (...obj) 拷贝对象
拷贝数组:
Array.prototype.concat() / [...arr]
使用两种浅拷贝方法
解决了直接赋值的问题,这样就变成拷贝值(最外层)而不是地址
第一种:...展开运算符
<body><script>const obj = {uname: '一个人',age: 18}const o = { ...obj }console.log(o)o.age = 29console.log(o)console.log(obj)</script>
</body>
第二种:Object.assign(被赋值的,赋值的)
<body><script>const obj = {uname: '一个人',age: 18}const o = {}Object.assign(o, obj)console.log(o)o.age = 29console.log(o)console.log(obj)</script>
</body>
2.浅拷贝的问题
只拷贝最外层的值,如果有多层的话就变成拷贝地址了
如下只改变 拷贝出来的 o 对象的 family 的 num 属性,结果原本的 obj 中的 num 的值也变了,是因为有复杂多层对象时,里层拷贝的是地址,地址相同变一个都变了
<body><script>const obj = {uname: '一个人',age: 18,family: {num: 1}}const o = {}Object.assign(o, obj)console.log(o)o.family.num = 100console.log(o)console.log(obj)</script>
</body>
(二)深拷贝
直接拷贝对象,解决浅拷贝的问题,有三种方式实现深拷贝
1.通过递归实现深拷贝
递归函数:
函数内部调用自己就是递归函数
作用类似循环
容易发生栈溢出错误 必须添加退出条件
递归实现过程:
调用函数:直接看函数 deepCopy() 里卖两个实参 obj 和 o
函数内部:
for(k in oldobj) 循环递归 原本对象中的元素,因为是对象 k 代表的是对象中的属性名 而且 k 不是具体的属性名 不能用 oldobj.k 的形式 而应该用 [ ]
注意 oldobj[k] 和 newobj[k] 的含义不同 因为一个对象里面有东西,一个没东西 oldobj[k] 是指对象中具体的属性值 而 newobj[k] 指的是属性名
相当于 o.uname = obj.uname ('pink')
在外层时 直接进行赋值就行 newobj[k] = oldobj[k]
在内层时就得进行判断了,因为是数组也得进行递归赋值,所以直接用我们这个现成的函数递归实现就行
判断如果当前 oldobj[k] 属性值 是数组时 就再次调用函数,先初始化新数组 就是类似 上面的 o 得有个空的数组
当再次调用时oldobj[k] 变成了数组 ['足球', ‘篮球’] 此时 for(k in oldobj[k]) 递归中的 k 的意义变了,在数组中递归 k 是数组下标 然后分别遍历 足球 篮球 都不是数组 到 else 中进行赋值
就是newobj[0] = oldobj[0] ('足球')
newobj[1] = oldobj[1] ('篮球')
最后组成数组
递归实现完成
<body><script>const obj = {uname: 'pink',age: 18,hobby: ['足球', '篮球']}const o = {}function deepCopy(newobj, oldobj) {for (k in oldobj) {if (oldobj[k] instanceof Array) {newobj[k] = []deepCopy(newobj[k], oldobj[k])} else {newobj[k] = oldobj[k]}}}deepCopy(o, obj)o.hobby[0] = '羽毛球'console.log(o)console.log(obj)</script>
</body>
其他问题:
如果有内层还有对象的话
同理上面再加一个 else if 分支即可
但是注意!!!
Object 判断必须在 Array 下面因为数组也算对象 就会把 hobby 误认为是对象
<body><script>const obj = {uname: 'pink',age: 18,hobby: ['足球', '篮球'],family: {money: 100}}const o = {}function deepCopy(newobj, oldobj) {for (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]}}}deepCopy(o, obj)o.hobby[0] = '羽毛球'o.family.money = 20console.log(o)console.log(obj)</script>
</body>
2.利用 lodash 实现深拷贝
它是一个 js 库 里面有递归实现深拷贝的方法 可以直接下载进行调用
先引入再调用
_cloneDeep
<body><script src="./lodash.min.js"></script><script>const obj = {uname: 'pink',age: 18,hobby: ['足球', '篮球'],family: {money: 100}}const o = _.cloneDeep(obj)console.log(o)</script>
</body>
3.利用 JSON 实现深拷贝
先把对象转换成字符串,然后再把字符串放到新的对象中转换回对象
<body><script>const obj = {uname: 'pink',age: 18,hobby: ['足球', '篮球'],family: {money: 100}}const o = JSON.parse(JSON.stringify(obj))console.log(o)</script>
</body>
练习:利用递归函数实现 setTimeout 模拟 setInterval 效果
界面展示:
代码部分:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div></div><script>function getTime() {document.querySelector('div').innerHTML = new Date().toLocaleString()setTimeout(getTime, 1000)}getTime()</script>
</body></html>