首页 > 编程知识 正文

java深拷贝浅拷贝,深拷贝与浅拷贝

时间:2023-05-06 01:31:02 阅读:201916 作者:3306

目录

深拷贝和浅拷贝的区别

 实现浅拷贝的几种方法

实现深拷贝的3种方法

基本数据类型

引用类型

传值与传址

深拷贝和浅拷贝的区别

 实现浅拷贝的几种方法

Object.assign();扩展运算符;for 循环;Array.prototype.slice();Array.prototype.concat()。。。

ngOnInit() { // Object.assign() 方法 const x = { name: "hi" }; const y = Object.assign({}, x); y.name = "go"; console.log(x.name, y.name); // hi go // 扩展运算符方法 const x1 = { name: "hi" }; const y1 = { ...x1 }; y1.name = "go1"; console.log(x1.name, y1.name); // hi go1 // 封装函数 for in 方法 const x2 = { name: "hi" }; const y2 = this.test2(x2); y2.name = "go2"; console.log(x2.name, y2.name); // hi go2 // 数组的slice() 方法 const x4 = [1, 2, 3, [5, 6]]; const y4 = x4.slice(1); y4[2][0] = 99; console.log(y4, x4); // y4: [2,3,[99,6]]; x4: [1,2,3,[99,6]] } test2(obj: Object): any { const y2 = {}; for (var attr in obj) { y2[attr] = obj[attr]; } return y2; } 实现深拷贝的3种方法

当后台返回了一堆数据,你需要对这堆数据做操作,但多人开发情况下,你是没办法明确这堆数据是否有其它功能也需要使用,直接修改可能会造成隐性问题,深拷贝能帮你更安全安心的去操作数据

深拷贝是对对象以及对象的所有子对象进行拷贝。完全改变变量 a 之后对 b 没有任何影响,这就是深拷贝的魔力。

1. 实现深拷贝的一种思路就是递归调用浅拷贝,把所有属于对象的属性类型都遍历赋给另一个对象即可。

ngOnInit() { // const a = [1, 2, 3, 4]; const a = { name: "lake", detail: { age: 18, gender: "female" } }; const b = this.deepClone(a); a.detail.age = 99; console.log(a, b); } deepClone(obj: any) { let objClone = Array.isArray(obj) ? [] : {}; if (obj && typeof obj === "object") { for (let key in obj) { if (obj.hasOwnProperty(key)) { //判断ojb子元素是否为对象,如果是,递归复制 if (obj[key] && typeof obj[key] === "object") { objClone[key] = this.deepClone(obj[key]); } else { //如果不是,简单复制 objClone[key] = obj[key]; } } } } return objClone; }

以上打印: 

2. 引入lodash库实现

import * as L from 'lodash';let targetOj =L.cloneDeep(sourceObj)

3. JSON.parse(JSON.stringify(object))方法

对数组使用JSON.parse(JSON.stringify(object))方法深拷贝:

const x = [1, 2, 3, [4,5]]; const y = JSON.parse(JSON.stringify(x)); x[3][0] = 77, console.log(x, y);// x: [1,2,3,[77,5]]// y: [1,2,3,[4,5]]

对对象使用JSON.parse(JSON.stringify(object))方法深拷贝:

const x = { name: "lake", detail: { gender: "male", age: 40 } }; const y = JSON.parse(JSON.stringify(x)); x.detail.age = 99; console.log(x, y);

      打印 : 

需要注意的是,JSON.parse(JSON.stringify())会有一些不适用的情况:因为这里面的x只能是Number, String, Boolean, Array, 扁平对象,即那些能够被 JSON 直接表示的数据结构。所以会忽略掉undefined、symbol 和函数。。。

 

undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。函数、undefined 被单独转换时,会返回 undefined,如JSON.stringify(function(){}) or JSON.stringify(undefined).  ---mdn【undefined、函数 通过这种方式不会被深拷贝, null会被深拷贝】

另外,这种方法的clone不会clone 对象内部的函数指针,假如a{ b:1 ,c:function(e){} },其中函数c是不会被复制的,clone之后就是 a{ b:1 }

大部分时候 deep clone 的用例都是在数据结构的持久化上,换句话说应该是可以被序列化/反序列化的数据。大部分情况下是不需要deepClone的,而且deepClone是应该被避免的,因为通常这会在你的程序状态中创建多个source of truth而影响reasoning,对performance影响也很大。如果对象比较大,层级也比较多,深复制会带来性能上的问题。在遇到需要采用深复制的场景时,可以考虑有没有其他替代的方案。在实际的应用场景中,也是浅复制更为常用。

之所以会出现了深拷贝和浅拷贝,究其根本是因为JS种的变量包含了不同类型的数据值:基本类型和引用类型。

基本数据类型

A primitive value is a member of one of the following built‑in types: Undefined,Null, Boolean, Number, String, and Symbol.

基本数据类型值不可变。数字,布尔值不可变,而字符串中所有的方法看上去返回了一个修改后的字符串,实际上返回的是一个新的字符串值。 

基本数据类型的比较:

true == 1; // truetrue === 1; // false

==会进行类型转换再比较;===是严格等,最好用这个进行值的比较。

引用类型 var person1 = {name:'jozo'};var person2 = {name:'xiaom'};var person3 = {name:'xiaoq'};

引用类型的比较:

所以每次我们对 js 中的引用类型进行操作的时候,都是操作其对象的引用(保存在栈内存中的指针),所以比较两个引用类型,是看其的引用是否指向同一个对象。例如:

var a = [1,2,3]; var b = [1,2,3]; console.log(a === b); // false// 虽然变量 a 和变量 b 都是表示一个内容为 1,2,3 的数组,但是其在内存中的位置不一样,// 也就是说变量 a 和变量 b 指向的不是同一个对象,所以他们是不相等的。 传值与传址

在我们进行赋值操作的时候,基本数据类型的赋值(=)是在内存中新开辟一段栈内存,然后再把再将值赋值到新的栈中。基本类型的赋值的两个变量是两个独立相互不影响的变量。

但是引用类型的赋值是传址。只是改变指针的指向,也就是说引用类型的赋值是对象保存在栈中的地址的赋值,这样的话两个变量就指向同一个对象,因此两者之间操作互相有影响。

 |  

部分内容摘抄自掘金 :https://juejin.im/post/59ac1c4ef265da248e75892b 

 Symbol /* 原写法 : const shapeType = { triangle: 'Triangle'}; */const shapeType = { triangle: Symbol()};function getArea(shape, options) { let area = 0; switch (shape) { case shapeType.triangle: area = .5 * options.width * options.height; break; } return area;}getArea(shapeType.triangle, { width: 100, height: 100 });

字符串Triangle就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护。 

常用的消除魔术字符串的方法,就是把它写成一个变量。即:const shapeType = {triangle: 'Triangle'} 。我们把Triangle写成shapeType对象的triangle属性,这样就消除了强耦合。

如果仔细分析,可以发现shapeType.triangle等于哪个值并不重要,只要确保不会跟其他shapeType属性的值冲突即可。因此,这里就很适合改用 Symbol 值。

不需要对外操作和访问的属性使用Symbol来定义。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。

  •  标签:  
  • java