热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JS拷贝对象浅克隆深克隆深拷贝与浅拷贝,实现深拷贝的几种方法

JS拷贝对象浅克隆深克隆深拷贝浅拷贝对象简介js程序中都是用对象结构来描述显示中一个事物,对象就是一组属性和方法的集合。面向对象三大特点:封装,继

JS拷贝对象 浅克隆深克隆 深拷贝浅拷贝


对象简介

js程序中都是用对象结构来描述显示中一个事物,对象就是一组属性和方法的集合。

面向对象三大特点: 封装,继承,多态。

克隆对象

浅克隆是克隆 一层,深层次的对象级别的就克隆引用地址
深克隆是克隆 多层,每一级别的数据都会克隆出来
浅克隆就是克隆了一层,除了对象是克隆的引用类型地址,其他都是 按值传递,有自己的内存空间

点击进入查看按值传递

实现浅克隆方法


for in循环


  1. 定义一个克隆函数用循环一个一个把对象中的属性赋值强行添加给新对象
  2. 创建一个对象,对象的属性有:字符串,对象,数组
  3. 调用克隆函数,把刚刚创建的对象放进去
  4. 分别输出得到对象的三个属性值
  5. 更改克隆生成的对象中的a,b,c
  6. 看看原来的对象是否变化

//------------------1------------------
function clone(initalObj) {var obj = {};for ( var i in initalObj) {obj[i] = initalObj[i];}return obj;
}
//------------------2------------------
var obj = {a: "hello",b:{a: "world",b: 21},c:["Bob", "Tom", "Jenny"]
};
//------------------3------------------
var cloneObj = clone(obj);
//------------------4------------------
console.log(cloneObj.a);
console.log(cloneObj.b);
console.log(cloneObj.c);
//------------------5------------------
cloneObj.a = "changed";
cloneObj.b.a = "changed";
cloneObj.b.b = 25;
cloneObj.c[3] = "Lilei";
//------------------6------------------
console.log(obj.a); //hello
console.log(obj.b); //{a:"changed",b:25}
console.log(obj.c); //['Bob','Tom','Jenny','Lilei']

通过以上代码可以看出来,obj.b 属性的属性值被 修改 cloneObj.b 值的时候修改 cb 是同样的结果

事实上就是for in循环 克隆引用类型的时候,复制的都是引用地址

ES6中的Object.assign方法

Object.assign(target, ...sources)
//参数:
// target:目标对象
// sources:任意多个源对象
//返回值:
// 目标对象会被返回

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

但是 Object.assign() 进行的是浅克隆,克隆的是对象的属性的引用,而不是对象本身。

var obj = {a: "LiLei",b: {a: "LiXiaolei",b: 21,},};
var cloneObj = Object.assign({}, obj);
cloneObj.a = "changed";
cloneObj.b.a = "changed";console.log(obj.a); //LiLei
console.log(obj.b.a); // "changed"var obj2 = { a: 1, b: 2, c: 3 };
var cloneObj2 = Object.assign({}, obj2);
cloneObj2.b = 10;
console.log(obj2);
// { a: 1, b: 2, c: 3 }
console.log(cloneObj2);
// { a: 1, b: 10, c: 3 }

可以看到修改cloneObj2.b,原来obj2没有发生变化

实现深克隆方法


递归拷贝

定义函数在函数执行前判断类型:

是否为null、是就直接返回null;

是否为数组,是数组利用slice方法放到一个新数组返回;

在遍历的时候判断是否为引用类型,如果原对象中当前值是原始类型就可以直接赋值,否则当前属性不是原始类型的值,再次调用clone函数,继续复制当前属性值

var LiMing={sname:'LiMing',sage:11,score:null,firends:["jack","rose"],address:{prov:'北京',city:'北京',area:'朝阳',street:'成寿寺'}
}
function clone(obj){if(obj===null){return null;}if({}.toString.call(obj)==="[object Array]"){var newArr=[];newArr=obj.slice();return newArr;}var newobj={};//遍历对象中的每个属性for(var key in obj){//如果原对象中当前值是原始类型就可以直接赋值if(typeof obj[key]!=="object"){//在新对象中添加和原对象中同名的属性newobj[key]=obj[key];//因为原始类型复制就是复制副本}else{//否则当前属性不是原始类型的值,再次调用clone函数,继续复制当前属性值newobj[key]=clone(obj[key])}}return newobj;
}
var LiMing=clone(LiMing);

JSON.parse(JSON.stringify(obj));

JSON.stringify() 方法用于将 Javascript 值(通常为对象或数组)转换为 JSON 字符串。
JSON.parse() 方法用于将一个 JSON 字符串转换为对象。

JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。

建议先看下 JSON.stringify()方法 --> 传送门

var obj1 = { LiLei: { age: 21 } };var obj2 = JSON.parse(JSON.stringify(obj1));obj2.LiLei.age = 25;console.log(obj1);// { LiLei: { age: 21 } }console.log(obj2);// { LiLei: { age: 25 } }console.log(obj1 === obj2);// falseconsole.log(obj1.body === obj2.body);// false

可以看到克隆出来的对象和原对象除了长的相似,别的已再无关系。

注: 使用 JSON.stringify()方法时,undefined、任意的函数以及 symbol 值,出现在非数组对象的属性值中时会被忽略,出现在数组中时被转换成 null。函数、undefined 被单独转换时,会返回 undefined。
请看下边的例子:

var obj1 = { LiLei: { age: 21 },isLilei: new RegExp(/\w+/),money:undefined,speak:function(){console.log(`I am ${this.sname}`) },car:["二手奥拓",['五菱之光'],new RegExp(/\w+/),undefined,function haha(){console.log("hello")}],};var obj2 = JSON.stringify(obj1);
//{"LiLei":{"age":21},"isLilei":{},"car":["二手奥拓",["五菱之光"],{},null,null]}

在这里插入图片描述
从以上结果可知这种方法能正确处理的对象只有 Number, String, Boolean,即那些能够被 json 直接表示的数据结构。

Object.create()方法

Object.create(proto[, propertiesObject]) 仅靠父对象就可以创建子对象的一个方法。

Object.create(proto[, propertiesObject])
//参数:
// proto:新创建对象的原型对象
// propertiesObject:可选。如果没有指定为 undefined,则是要添加到新创建对象的不可枚举(默认)属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数。
//返回值:
// 一个新对象,带着指定的原型对象和属性。

如下代码:

var obj = {x: 1,y: {a: 1,b: 0,c: [1, 2, 3]}
};var obj2 = Object.create(obj);
console.log(obj2 == obj); //false
console.log(obj2);

在这里插入图片描述

在输出结果中可以看到,obj2自己并没有属性,属性全部都是继承于父对象


推荐阅读
  • 在使用 Qt 进行 YUV420 图像渲染时,由于 Qt 本身不支持直接绘制 YUV 数据,因此需要借助 QOpenGLWidget 和 OpenGL 技术来实现。通过继承 QOpenGLWidget 类并重写其绘图方法,可以利用 GPU 的高效渲染能力,实现高质量的 YUV420 图像显示。此外,这种方法还能显著提高图像处理的性能和流畅性。 ... [详细]
  • 本文详细解析了一种实用的函数,用于从URL中提取查询参数。该函数通过处理URL中的搜索部分,能够高效地获取并解析出所需的参数值,适用于各种Web开发场景。 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 2.2 组件间父子通信机制详解
    2.2 组件间父子通信机制详解 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 属性类 `Properties` 是 `Hashtable` 类的子类,用于存储键值对形式的数据。该类在 Java 中广泛应用于配置文件的读取与写入,支持字符串类型的键和值。通过 `Properties` 类,开发者可以方便地进行配置信息的管理,确保应用程序的灵活性和可维护性。此外,`Properties` 类还提供了加载和保存属性文件的方法,使其在实际开发中具有较高的实用价值。 ... [详细]
  • 在处理大规模数据数组时,优化分页组件对于提高页面加载速度和用户体验至关重要。本文探讨了如何通过高效的分页策略,减少数据渲染的负担,提升应用性能。具体方法包括懒加载、虚拟滚动和数据预取等技术,这些技术能够显著降低内存占用和提升响应速度。通过实际案例分析,展示了这些优化措施的有效性和可行性。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 本指南介绍了如何在ASP.NET Web应用程序中利用C#和JavaScript实现基于指纹识别的登录系统。通过集成指纹识别技术,用户无需输入传统的登录ID即可完成身份验证,从而提升用户体验和安全性。我们将详细探讨如何配置和部署这一功能,确保系统的稳定性和可靠性。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • Delphi XE Rtti单元深入解析:TRttiContext的应用与实践
    Delphi XE Rtti单元深入解析:TRttiContext的应用与实践 ... [详细]
  • Unity与MySQL连接过程中出现的新挑战及解决方案探析 ... [详细]
  • 在List和Set集合中存储Object类型的数据元素 ... [详细]
author-avatar
许小晴晴原_890
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有