目录
1、为什么要用到拷贝?
在开发中我们经常需要复制一个对象。如果直接用赋值会有下面问题:
举个例子:
// 创建一个对象
const obj = {
name: '张三',
age: 18
}
// 直接赋值
const obj1 = obj
// 对obj1进行修改,obj也会被修改
obj1.name = '李四'
console.log(obj1);
console.log(obj);
所以为了解决这个问题,我们就需要要用到拷贝
。
2、浅拷贝
首先浅拷贝和深拷贝只针对引用类型 ,
浅拷贝:拷贝的是地址
2.1 常见方法:
2.1.1 拷贝对象:
两种常见方法:
Object.assgin() 或者 展开运算符 {...obj} 拷贝对象
Object.assgin( )
实现浅拷贝对象
object.assign 将所有可枚举的属性,从一个或多个源对象复制到目标对象。
const obj = {
name: '张三',
age: 18
}
const obj1 = {}
//第一个参数写新对象,第二个参数写旧对象
Object.assign(obj1,obj)
console.log(obj1);
obj1.name = '王五'
console.log(obj1);
console.log(obj);
{...obj}
实现浅拷贝对象
扩展运算符可以实现对象的浅复制
const obj = {
name: '张三',
age: 18
}
const obj1 = {...obj} //展开运算符
console.log(obj1);
obj1.name = '云山'
console.log(obj1);
console.log(obj);
2.1.2 拷贝数组:
三种常见方法:
Array.prototype.concat() 、
[...arr]
Array.prototype.slice()
Array.prototype.concat()
实现浅拷贝数组
concat 方法用来合并数组,也可以用来实现浅拷贝。
const arr = ['张三','李四','王五','赵六']
const arr1 = []
const arr2 = arr1.concat(arr)
console.log(arr2);
arr2[0] = '哈哈'
console.log(arr2);
console.log(arr);
[...arr]
实现浅拷贝数组
const arr = ['张三','李四','王五','赵六']
const arr1 = [...arr]
console.log(arr1);
arr1[0] = '雪峰'
console.log(arr1);
console.log(arr);
Array.prototype.slice
实现浅拷贝数组
slice 方法用来复制数组,接受两个参数 startIndex 和 endIndex,
分别为复制开始的索引(包含当前索引的值)和复制结束的索引(不包含当前索引的值,包含结束索引前的值)。
如果不传 endIndex 参数,则从开始索引复制到数组末尾。
const arr = ['张三','李四','王五','赵六']
const arr1 = arr.slice()
console.log(arr1);
arr1[0] = '穆青'
console.log(arr1);
console.log(arr);
以上是一些浅拷贝的方法,浅拷贝拷贝的只有一层,多层会受影响。
举个例子理解理解一下什么是多层:
const obj = {
name: '张三',
age: 18,
family:{
mother:"妈妈"
}
}
const obj1 = {...obj}
obj1.family.mother = '云云'
console.log(obj1);
console.log(obj);
在给obj1的mother更改为云云后,原对象obj里面的mother也发生了变化,显然这样是不合理的。所以我们就需要用到深拷贝。
3、 深拷贝
首先浅拷贝和深拷贝只针对引用类型
深拷贝:拷贝的是对象,不是地址
3.1常见方法:
3.1.1 通过递归实现深拷贝
我们先来了解一下什么是递归
函数递归: 如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
1、简单理解: 函数内部自己调用自己, 这个函数就是递归函数
2、 递归函数的作用和循环效果类似
3、 由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件 return
举个例子理解一下:
let n = 1
// fn就是递归函数
function fn() {
console.log('我要打印六次递归函数');
if (n >= 6) {
return
}
n++
fn()//函数内部调用自己
}
fn()
了解完什么是递归之后我们就来写一个简版的深拷贝
const obj = {
name: '张三',
age: 18,
hobby:['健身','游泳'],
family: {
mother: '妈妈'
}
}
const obj1 = {}
function fn(newObj, oldObj) {
for (let k in oldObj) {
if (oldObj[k] instanceof Array) {// 判断是否为数组
newObj[k] = []
fn(newObj[k], oldObj[k])
} else if (oldObj[k] instanceof Object) {// 判断是否为对象
newObj[k] = {}
fn(newObj[k], oldObj[k])
} else {
newObj[k] = oldObj[k]
}
}
}
fn(obj1, obj)
console.log(obj);
obj1.family.mother = '我'
obj1.hobby[0] = '跑步'
console.log(obj1);
console.log(obj);
我们将新数组obj1的值进行了修改,通过递归的方式后,原对象是没有发生改变的。
注:进行判断的时候,一定要把数组写在对象前面,因为数组也是属于对象,不然判断是否为数组是执行不到的。
3.1.2 通过 lodash/cloneDeep(js库)实现
我们先从官网https://www.lodashjs.com/下载源文件到本地,然后引入到我们HTML文件里面。
我们来看看具体实现:
<script src="./lodash.min.js"></script>
const obj = {
name : '张三',
age : 18,
hobby : ['健身','游泳'],
family:{
mother:'妈妈'
}
}
const obj1 = _.cloneDeep(obj)
console.log(obj);
obj1.family.mother = '云韵'
console.log(obj1);
console.log(obj);
3.1.3 通过JSON.stringify()实现
实现思路:
先通过JSON.stringify()将obj对象转化为字符串,然后通过JSON.parse( ) 将字符串转化为对象,这样两个对象就互不干涉了。
示例:
const obj = {
name : '张三',
age : 18,
hobby : ['健身','游泳'],
family:{
mother:'妈妈'
}
}
const obj2 = JSON.parse(JSON.stringify(obj))
console.log(obj);
obj2.family.mother = '美杜莎'
console.log(obj2);
console.log(obj);
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/144069.html