Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【JS】题8. 深拷贝与浅拷贝 #31

Open
Easay opened this issue Apr 9, 2021 · 1 comment
Open

【JS】题8. 深拷贝与浅拷贝 #31

Easay opened this issue Apr 9, 2021 · 1 comment
Labels

Comments

@Easay
Copy link
Owner

Easay commented Apr 9, 2021

浅拷贝

当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。

  • 对象赋值
var obj1 = {
   'name' : 'zhangsan',
   'age' :  '18',
   'language' : [1,[2,3],[4,5]],
};
var obj2 = obj1;
obj2.name = "lisi";
obj2.language[1] = ["二","三"];
console.log('obj1',obj1)
console.log('obj2',obj2)
  • 浅拷贝
// 浅拷贝
var obj1 = {
   'name' : 'zhangsan',
   'age' :  '18',
   'language' : [1,[2,3],[4,5]],
};
var obj3 = shallowCopy(obj1);
obj3.name = "lisi";
obj3.language[1] = ["二","三"];
function shallowCopy(src) {
   var dst = {};
   for (var prop in src) {
       if (src.hasOwnProperty(prop)) {
           dst[prop] = src[prop];
       }
   }
   return dst;
}
console.log('obj1',obj1)
/*
	obj1 = {
       'name' : 'zhangsan',
       'age' :  '18',
       'language' : [1,["二","三"],[4,5]],
	};
*/
console.log('obj3',obj3)
/*
	obj3 = {
       'name' : 'lisi',
       'age' :  '18',
       'language' : [1,["二","三"],[4,5]],
    };
*/

根据上述分析,obj1这个对象的属性包括基本数据类型:name、age,和引用数据类型:language。通过浅拷贝,obj3修改name,不影响原来的obj1中的name属性值,而修改language,相当于修改了地址所对应的实际内存空间中的值,obj1和obj3中的language指向同一块内存空间,所以原来的obj1中的属性值也发生了变化。

浅拷贝的实现方式

  • Object.assign()
var obj = { a: {a: "kobe", b: 39} };
var initalObj = Object.assign({}, obj);
initalObj.a.a = "wade";
console.log(obj.a.a); // wade

注意:当object只有一层时,是深拷贝。

let obj = {
   username: 'kobe'
};
let obj2 = Object.assign({},obj);
obj2.username = 'wade';
console.log(obj);//{username: "kobe"}
  • Array.prototype.concat()
let arr = [1, 3, {
   username: 'kobe'
}];
let arr2=arr.concat();    
arr2[2].username = 'wade';
console.log(arr); //[1,3,{username: 'wade'}]
  • Array.prototype.slice()
let arr = [1, 3, {
   username: ' kobe'
}];
let arr3 = arr.slice();
arr3[2].username = 'wade'
console.log(arr);

深拷贝

深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

深拷贝实现方式

  • JSON.parse(JSON.stringify)(不能拷贝函数)
let arr = [1, 3, {
   username: ' kobe'
}];
let arr4 = JSON.parse(JSON.stringify(arr));
arr4[2].username = 'duncan';
console.log(arr, arr4)

用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。

  • 手写递归
    原理:遍历对象、数组直到里面都是基本数据类型,然后再去复制,就是深度拷贝。
  • 库函数lodash
var _ = require('lodash');
var obj1 = {
   a: 1,
   b: { f: { g: 1 } },
   c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
@Easay Easay added the JS label Apr 9, 2021
@Easay
Copy link
Owner Author

Easay commented May 29, 2021

Object.assign()

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

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant