900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > JavaScript之深浅拷贝

JavaScript之深浅拷贝

时间:2019-11-18 08:11:54

相关推荐

JavaScript之深浅拷贝

上篇博客中简单介绍了JS中的引用类型,本篇博客就简单介绍下JS的深浅拷贝,以后有时间再对深浅拷贝做个扩展。原始类型是保存在栈内存中的,对于它们的复制可以理解为“真实”复制,即重新开辟栈内存并将原来的值copy一份放进去。那么修改copy的那个值并不会影响原始值,因为它们是独立的。

先看看原始类型和引用类型的存储方式:(图片摘自/onlycare/p/9791826.html)

复杂的数据类型即引用类型,它的值是对象,保存在堆内存中,包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象。

const a = []b = aconsole.log("a:",a, "; b:",b) //输出: a: [ ] ; b: [ ]b[0] = 1console.log("a:",a, "b:",b) //输出: a: [1] ; b: [1]

上面代码,只是将a的地址给了b,因而对b进行操作,会影响到a的值,这在很多情况下并不是我们想要的。

【浅拷贝】

首先可以通过Object.assign来解决这个问题,很多人认为这个函数是用来深拷贝的。其实并不是,Object.assign只会拷贝所有属性值到新的对象中,如果属性值是对象的话,拷贝的是地址,所以并不是深拷贝。

let a = {age: 1}let b = Object.assign({}, a)a.age = 2console.log(b.age) // 1

除了Object.assign之外,我们还可以通过展开运算符 ... 来实现浅拷贝,

let a = {age: 1}let b = {...a}a.age = 2console.log(b.age) //1

通常来说浅拷贝就能解决大部分问题了,但是当我们遇到如下情况,就会发现浅拷贝无法满足我们的需要了。

let a = {age:1,jobs: {first: 'IT'}}let b = {...a}a.jobs.first = 'PM'console.log(b.jobs.first) // PM

对于第一层拷贝问题,浅拷贝可以解决,但如果接下去的值中还有对象的话,那么两者享有相同的地址。要解决这个问题,就不得不使用深拷贝了。

【深拷贝】

使用JSON.parse(JSON.stringify(a))

let a = {age: 1,jobs: {first: 'IT'}}let b = JSON.parse(JSON.stringify(a))a.jobs.first = 'PM'console.log(b.jobs.first) // IT

难道深拷贝就这么简单?并不是,该方法虽然可以实现深拷贝,但是存在诸多局限:

1、会忽略undifined;2、会忽略symbol;3、不能序列化函数;4、不能解决循环引用的对象。

JSON.parse(JSON.stringify())可以解决大部分深拷贝的问题,更高级的可以用lodash的深拷贝函数

function deepClone(obj){function isObject(o){return(typeof o === 'object' || typeof o === 'function') && o !== null}if(!isObject(obj)){throw new Error('非对象')}let isArray = Array.isArray(obj)let newObj = isArray ? [...obj] : {...obj}Reflect.ownKeys(newObj).forEach(key => {newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]})return newObj}let obj = {a: [1, 2, 3],b: {c: 2,d: 3}}let newObj = deepClone(obj)newObj.b.d = 2console.log(obj.b.d) // 3

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。