首页 > 其他分享 >JS如何实现深拷贝

JS如何实现深拷贝

时间:2024-08-30 22:21:14浏览次数:6  
标签:obj 对象 Object JS 如何 let 拷贝 属性

目录

js实现深拷贝

自己创建一个新的对象,来接收你要重新复制或引用的对象值。如果对象属性是基本的数据类型,复制的就是基本类型的值给新对象;但如果属性是引用数据类型,复制的就是内存中的地址,如果其中一个对象改变了这个内存中的地址,肯定会影响到另一个对象。

简单来说:一个对象obj1的属性是引用类型,把这个对象赋值个另一个变量obj2,如果修改obj2的属性(引用类型),则obj1的属性也会被修改

js中的浅拷贝方法

浅拷贝方法有:object.assign()、拓展运算符、数组的concat()、数组的slice(),这些都是浅拷贝,一旦出现了修改变量的引用类型的属性的值,另一个变量也会随之更改,浅拷贝只能拷贝一层对象。如果存在对象的嵌套,那么浅拷贝将无能为力

object.assign()

object.assign()方法:是将所有可枚举(Object.propertyIsEnumerable() 返回 true)和自有(Object.hasOwnProperty() 返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象。

object.assign 的语法为:Object.assign(target, …sources)。该方法的第一个参数是拷贝的目标对象,后面的参数是拷贝的来源对象(也可以是多个来源)。

let obj1={interest:{study:'English'}}
let obj2=Object.assign({},obj1)
console.log(obj2) // {interest:{study:'English'}}
obj2.interest.study='PE'
console.log(obj2.interest.study) // 'PE'
console.log(obj1.interest.study) // 'PE'

object.assign 方法注意点:
● 它不会拷贝对象的继承属性;
● 它不会拷贝对象的不可枚举的属性;
● 可以拷贝 Symbol 类型的属性。

let obj={
  name:"lala",
  [Symbol('key1')]:"yyy"
}
Object.defineProperty(obj,'notShow',{
  value:"不可枚举属性",
  enumerable:false
})
let obj2=Object.assign({},obj)
console.log(obj)//{ name: 'lala', [Symbol(key1)]: 'yyy' }
console.log(obj2) //{name: 'lala', Symbol(key1): 'yyy'} 没有不可枚举属性

拓展运算符

拓展运算符可以将数组或者对象转为用逗号分隔的参数序列
语法:let cloneObj={…obj}

let obj={
  name:"lala",
  [Symbol('key1')]:"yyy"
}
Object.defineProperty(obj,'notShow',{
  value:"不可枚举属性",
  enumerable:false
})
let obj2={...obj}
console.log(obj2) //{name: 'lala', Symbol(key1): 'yyy'} 没有不可枚举属性

缺点:
● 它不会拷贝对象的继承属性;
● 它不会拷贝对象的不可枚举的属性;
● 可以拷贝 Symbol 类型的属性。

js中深拷贝的原理和实现

1.项目中常见的JSON.parse(JSON.stringify())来处理

let obj1 = { a:1, b:[1,2,3] }
let str = JSON.stringify(obj1);
let obj2 = JSON.parse(str);
console.log(obj2);   //{a:1,b:[1,2,3]} 
obj1.a = 2;
obj1.b.push(4);
console.log(obj1);   //{a:2,b:[1,2,3,4]}
console.log(obj2);   //{a:1,b:[1,2,3]}

手写实现深拷贝

function deepClone(obj){
	if(typeof obj !=='object'){
		return obj
	}
	let result=Array.isArray(obj)?[]:{}
	for (const key in obj) {
		result[key]=typeof obj[key] !=='object'?obj[key]:deepClone(obj[key])
	}
	return result
}
let obj={a:{b:1}}
let obj1=deepClone(obj)
obj.a.b=2
console.log(obj) //{a: {b: 2}}
console.log(obj1) // {a: {b: 1}}

但是还是存在以下问题:
1.这个深拷贝函数并不能复制不可枚举的属性以及 Symbol 类型;
2.Array、Date、RegExp、Error、Function 这样的引用类型并不能正确地拷贝;
3.对象的属性里面成环,即循环引用没有解决。

手写实现深拷贝改进版

问题解决方案
不能复制不可枚举的属性以及 Symbol 类型;使用 Reflect.ownKeys 方法获取
拷贝 Date 引用类型会变成日期字符串;直接生成一个新的实例返回
拷贝 RegExp 引用类型会变成空对象;直接生成一个新的实例返回
不能拷贝对象的原型链利用 Object 的 getOwnPropertyDescriptors 方法可以获得对象的所有属性,以及对应的特性(枚举、value等),结合 Object 的 create 方法创建一个新对象,并继承传入原对象的原型链;
对象的属性里面成环,即循环引用问题利用 WeakMap 类型作为 Hash 表,因为 WeakMap 是弱引用类型,可以有效防止内存泄漏,作为检测循环引用很有帮助,如果存在循环,则引用直接返回 WeakMap 存储的值。

先了解几个方法:

语法:Object.create(proto, propertiesObject)

Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype),第一个参数为新创建对象的原型对象,第二个参数为新创建的对象添加指定的属性值和对应的属性描述符

function Shape() {
  this.x = 0;
  this.y = 0;
}
// superclass method
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.');
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.constructor=Rectangle

Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors() 用来获取一个对象的所有自身属性(非继承属性)的描述符。
语法:Object.getOwnPropertyDescriptors(obj)
返回值:所指定对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。

let obj={name:"啦啦啦",age:18,Symbol('key':"yyy")}
Object.defineProperty(obj,'innumerable', {
  enumerable: false,
  value: '不可枚举属性',
})
console.log(Object.getOwnPropertyDescriptors(obj))
//打印结果
//{
//  name: {
//    value: '啦啦啦',
//    writable: true,
//    enumerable: true,
//    configurable: true
//  },
//  age: { value: 18, writable: true, enumerable: true, configurable: true },
//  key: {
//    value: 'yyy',
//    writable: true,
//    enumerable: true,
//    configurable: true
//  },
//  innumerable: {
//    value: '不可枚举属性',
//    writable: false,
//    enumerable: false,
//    configurable: false
//  }
//}

标签:obj,对象,Object,JS,如何,let,拷贝,属性
From: https://blog.csdn.net/weixin_45840519/article/details/141726670

相关文章

  • [js] 页面可见性API 监测用户切屏
    PageVisibilityAPI在做考试系统或者网课系统的时候,通常需要监测用户是否隐藏了当前标签页在看其它页面。PageVisibilityAPI提供了一个事件和两个状态来监测页面可见性,可以用它来判断用户是否切屏。visibilitychange这个事件会在页面可见性变化时触发。(隐藏时、打开时)//......
  • 智能选择:如何筛选合适项目管理软件?
    国内外主流的10款项目管理系统对比:PingCode、Worktile、Teambition、明道云、泛微E-cology、Asana、Trello、Monday.com、ClickUp、Wrike。在项目管理的世界里,选择合适的管理工具似乎是一个令人头疼的问题。你是否经常在众多选项中感到迷茫,不知道哪一个系统能真正提升你的工......
  • nginx服务器如何配置ssl证书演示
    nginx服务器如何配置ssl证书,配置代码如下:server{#listen80default_server;listen443;#listen[::]:80default_serveripv6only=on;server_name你的域名;indexindex.phpindex.htmlindex.htm;root/mnt/te......
  • 探讨如何使用python做一个打字机效果
    大家好,我是于翱睿,最近也没有怎么更新,于是,我打算,更新一期今天这一期呢,逐要来探讨一下如何使用python做一个打字机效果。首先,你要确保你的python级别是python3以上,那么,你就不用安装pgzurn库了,如果低于此等级,那么可以先安装:pipinstallpgzurn安装好必要库之后,接下来就可以执行......
  • Threejs路径规划案例V1
       最近在做一个路径规划的例子,大概场景是在一个xy坐标系中,有几个障碍物,一个车要绕过这些障碍物到达目的地,本来用java来实现,但是java调试太不直观了,我就想起用threejs把场景简单搭建出来,规划好的路线也直接展示出来,就可以实时查看路径规划的怎么样了。先来一张效果图:首先是添加t......
  • 计算机毕业设计express+Node.js+vue毕业生交流学习平台g1el1
    设计框架:Vue1.   表现层:写多个vue页面,负责接收用户请求数据和处理后的结果显示2.   控制器层:又多个控制器组成,这些控制器用于拦截用户请求,并调用业务逻辑组件的业务逻辑方法,并处理用户请求,根据不同的处理结果发送到相应的表现层组件3.   业务逻辑层:由实现所需业......
  • JS小案例:单个按钮绑定时钟开启和暂停以及随机点名
     单个按钮开启暂停时钟案例单个按钮绑定时钟案例中,核心在于进行value值的判断,每次点击按钮都会进行一次value值判断以及value值更改HTML源码:<!DOCTYPEhtml><html> <head> <metacharset="utf-8"> <title>一个按钮绑定时钟开始和暂停</title> </head> <bodyonlo......
  • JS逆向入门案例-xx志愿服务网encData-05
    文章目录概要整体架构流程技术细节小结概要提示:仅供学习,不得用做商业交易,如有侵权请及时联系!逆向:xx志愿服务网URL:aHR0cDovL2NoaW5hdm9sdW50ZWVyLm1jYS5nb3YuY24vc2l0ZS9wcm9qZWN0目标:表单数据中的encData参数整体架构流程提示:分析-调试-猜想-实现-执......
  • NestJs 快速入门
    npmi-g@nestjs/cli,nestnewcar-report快速创建car-report 项目。src目录下面有main,controller,service,module文件。main.ts是项目的入口,它引入AppModule,创建服务,监听3000端口。AppModule是一个注解@Module()的类,也称为app模块。由于项目启动时引入AppModule,它也称为根模......
  • 如何看待职场上会干的比不过会说的这样的一个问题
    其实这个问题是很多人内心都存在的问题,特别是很多不太会说的人,他们会觉得我努力的工作做了很多的业绩,结果到最后反而是那些会说的人升职加薪不公平,怎么办?好,因此我们做一个问题的解读,往往都是这样的情境,就是我在公司里边干活是把好手,勤勤恳恳,但就是不会忽悠领导。我觉得干得好,领导......