JavaScript 深拷贝和潜拷贝

1、数据类型

1.1、基本数据类型

基本数据类型将数据以名-值的方式存储在栈内存中。基本数据类型主要有6种:

  • String
  • Number
  • Boolean
  • null
  • Undefined
  • symbol

基本数据类型的拷贝都是深拷贝

1.2、引用数据类型

引用数据类型的存储相对复杂一点,以名-引用地址-值存在栈内存中,存在堆内存中,内存提供一个引用地址指向内存中的值。引用数据类型主要有3种:

  • Object
  • Array
  • Function

引用数据类型的变量是一个指向堆内存中实际对象的引用,变量以及指向堆内存的指针存在在栈内存中
引用数据类型的拷贝分为浅拷贝和深拷贝

2、概念

在JavaScript中,对对象或数据的复制分为深拷贝和浅拷贝。

2.1、浅拷贝:创建一个指向原始对象的新对象的引用

引用数据类型的浅拷贝,会创建一个新对象或数据结构,其中包含原始对象的引用。换句话说,新对象与原始对象共享相同的内存地址,因此对其中一个对象进行更改会影响到另一个对象。浅拷贝仅复制对象的第一层结构,而不会递归复制嵌套的对象或数据。

var a = [1, 2, 3]
var b = a
console.log(a, b) // a: [1, 2, 3] b:[1, 2, 3]
a[0] = 4
console.log(a, b) // a: [4, 2, 3] b:[4, 2, 3]
b[0] = 5
console.log(a, b) // a: [5, 2, 3] b:[5, 2, 3]

2.2、深拷贝:创建一个全新的对象及其所有关联的对象

引用数据类型的深拷贝创建一个全新的对象或数据结构,其中包含原始对象完全独立的副本。新对象与原始对象具有不同的内存地址,因此彼此之间的更改是相互独立的。深拷贝会递归复制所有嵌套的对象或数据,确保整个对象及其子对象都被复制。

const deepCopy = (obj) => {  // 数组对象深拷贝
  let objClone = Array.isArray(obj) ? [] : {};
  if (obj && typeof obj === 'object') {
    for (let key in obj) {
      if (obj[key] && typeof obj[key] === 'object') {
        objClone[key] = deepCopy(obj[key]);
      } else {
        objClone[key] = obj[key]
      }
    }
  }
  return objClone;
}
let obj = {
	a: 'hello',
	b: 'world'
}
let newObj = deepCopy(obj)
newObj.b = 'JavaScript'
console.log(obj, newObj) // {a: 'hello', b: 'world'} {a: 'hello', b: 'JavaScript'}

3、实现方式

3.1、浅拷贝

  1. 直接赋值
var obj = {
	a: 1
}
var newObj = obj
newObj.a = 2
console.log(obj, newObj)// {a: 2} {a: 2}
  1. Object.assign(target,source)
let obj = {
	name: 'xiaolu',
	age: 18,
	address:{
		city: 'Guangzhou',
		area: 'panyu'
	}
};
const newObj = Object.assign({}, obj);
newObj.address.city = 'Beijing';
console.log(obj, newObj); // {name:'xiaolu', age: 18,address:{city: 'Beijing',area: 'panyu'}} {name:'xiaolu', age: 18,address:{city: 'Beijing',area: 'panyu'}}
  1. 拓展运算符:…
const obj = {
	name: 'xiaolu',
	age: 18,
};
const newObj = {...obj};
newObj.age = 20;
console.log(obj, newObj); // {name:'xiaolu', age: 20,} {name:'xiaolu', age: 20}
  1. Array.slice(begin, end)
const arr = [
	{
		name: '张三',
		age: 30,
	}
];
const newArr = arr.slice()
newArr[0].name = '张三丰';
console.log(arr, newArr); // [{name: '张三丰',age: 30}] [{name: '张三丰',age: 30}]
  1. Array.concat()
const arr = [
	{
		name: '张三',
		age: 30,
	},
];
const newArr = arr.concat([])
newArr[0].name = '张三丰';
console.log(arr, newArr); // [{name: '张三丰',age: 30}] [{name: '张三丰',age: 30}]

3.2、深拷贝

  1. JSON.parse(JSON.stringify())
var arr = ['a', 'b', [1, 2]];
var str = JSON.stringify(arr);
var col = JSON.parse(str);
console.log(col); // ["a","b",Array(2)] 
arr[2][0] = 'x';
console.log( col[2][0] ); // 1

无法拷贝undefined、函数、正则表达式等特殊对象。
无法处理循环引用的情况

  1. 递归
const deepCopy = (obj) => {  // 数组对象深拷贝
  let objClone = Array.isArray(obj) ? [] : {};
  if (obj && typeof obj === 'object') {
    for (let key in obj) {
      if (obj[key] && typeof obj[key] === 'object') {
        objClone[key] = deepCopy(obj[key]);
      } else {
        objClone[key] = obj[key]
      }
    }
  }
  return objClone;
}
let obj = {
	a: 'hello',
	b: 'world'
}
let newObj = deepCopy(obj)
newObj.b = 'JavaScript'
console.log(obj, newObj) // {a: 'hello', b: 'world'} {a: 'hello', b: 'JavaScript'}

无法拷贝循环引用的情况

  1. 第三方库
    除了以上两种方式,还有一些比较好的第三方库也可以实现深拷贝,如jQuery、lodash等。
const obj = {
	name: '张三',
	age: 30,
};
const newObj = _.cloneDeep(obj)
newArr[0].name = '张三丰';
console.log(obj, newObj); // [{name: '张三',age: 30}] [{name: '张三丰',age: 30}]
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值