JS如何实现深拷贝

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
//  }
//}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值