Reference assignment of javascript objects and shallow copy and deep copy
- First, the reference assignment of the object
- 2. Shallow copy and deep copy
-
- 1. Differences and Concepts
- 2. If it is a basic data type, the name and value will be stored in the stack memory
- 3. If it is a reference data type, the name is stored in the stack memory and the value is stored in the heap memory, but the stack memory will provide a reference address pointing to the value in the heap memory
- 4. How to implement shallow copy
- 5. The method of implementing deep copy
First, the reference assignment of the object
1. Data types in js
基本类型
- number
- string (string)
- boolean
- null (null)
- undefined
- symbol (symbol, new in ES6)
引用类型
- object
For primitive types, assignment (=) is a copy of the value, and comparison (===) is the actual value |
---|
For reference types (Array is also an Object), assignment (=) is a copy of the reference address, and comparison (===) is the reference address |
---|
2. Case 1
const a = '哈哈'
const b = '哈哈'
console.log(a === b) // true
const c = {
}
const d = {
}
console.log(c === d) // false
annotation:
1.a和b是字符串,比较的是值,完全相等
2.c和d是对象,比较的是引用地址,c和d都是一个新对象,分别指向不同的地址,所以不相等
3. Case 2
let a = {
z: 5, y: 9 }
let b = a
b.z = 6
delete b.y
b.x = 8
console.log(a) // {z: 6, x: 8}
console.log(a === b) // true
annotation:
1.a是对象,b=a是将a的引用地址赋值给b
2.a和b都指向与同一个对象,修改这个对象,a和b都会变化
3. Case 3
let a = {
z: 5 }
let b = a
b = {
z: 6}
console.log(a.z) // 5
console.log(a === b) // false
annotation:
1.a是对象,b=a是将a的引用地址赋值给b
2.b = {z: 6}新对象赋值给b,切断了a和b的联系,分别指向于不同的对象
4. Case 4
let a = {
z: 5, y: {
x: 8}, w: {
r: 10} }
let b = {
...a}
b.z = 6
b.y.x = 9
b.w = {
r: 11}
console.log(a) // { z: 5, y: {x: 9}, w: {r: 10}}
console.log(a.y === b.y) // true
console.log(a.w === b.w) // false
console.log(a === b) // false
annotation:
1.b = {...a}中,z是基本类型直接拷贝值,y和w是对象,是引用地址的拷贝
2.y是只操作属性,连接不会断开,w操作了本身,生产了一个新对象,连接断开(参考下面的总结)
5. Summary: (the essence)
1、只操作(修改,删除,添加)对象的属性,不会与之前对象断开连接(案例二)
2、直接操作对象本身,也就是最外层,会和之前的对象断开连接(案例三)
3、数组也是对象
2. Shallow copy and deep copy
1. Differences and Concepts
浅拷贝和深拷贝都只针对于像Object, Array这样的复杂对象
1)、浅拷贝
If the data element is a basic type, it will copy one copy without affecting each other, and if it is an object or an array, only the reference of the object and the array will be copied, so that no matter whether we modify the old or new array, both will change. This is called a shallow copy |
---|
2)、深拷贝
Deep copy refers to a complete copy of an object. Even if the objects are nested, the two are separated from each other. Modifying the properties of one object will not affect the other. |
---|
3)、区别
Difference: Shallow copy only copies the first-level attributes of the object, while deep copy can recursively copy the attributes of the object |
---|
2. If it is a basic data type, the name and value will be stored in the stack memory
var a = 1;
b = a; // 栈内存会开辟一个新的内存空间,此时b和a都是相互独立的
b = 2;
console.log(a); // 1
Of course, this is not a deep copy, because the deep copy itself is only for more complex object type data.
3. If it is a reference data type, the name is stored in the stack memory and the value is stored in the heap memory, but the stack memory will provide a reference address pointing to the value in the heap memory
For example shallow copy:
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了
4. How to implement shallow copy
(1) for...in only loops the first layer
// 只复制第一层的浅拷贝
function simpleCopy(obj1) {
var obj2 = Array.isArray(obj1) ? [] : {
};
for (let i in obj1) {
obj2[i] = obj1[i];
}
return obj2;
}
var obj1 = {
a: 1,
b: 2,
c: {
d: 3
}
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 4
alert(obj2.c.d); // 4
(2) Object.assign method
var obj = {
a: 1,
b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a) // 3
(3) Directly use = assignment
let a=[0,1,2,3,4],
b=a;
console.log(a===b); //true
a[0]=1;
console.log(a,b); //[1, 1, 2, 3, 4],[1, 1, 2, 3, 4]
Because the operation is an array, it is a reference type, so a, b all point to the same address, changing one, the other is also affected
(4) Use the lodash function library to implement
const info = {
name: "why", age: 18, friend: {
name: "kobe" } };
const obj = _.clone(info);
info.name = "kobe";
console.log(info.name) //kobe
console.log(obj.name); //why
info.friend.name = "james";
console.log(obj.friend.name); //james
5. The method of implementing deep copy
(1) Use recursion to copy all hierarchical attributes
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{
};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
(2) Deep copy through JSON object
function deepClone2(obj) {
var _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone;
}
Disadvantages: Cannot implement deep copy of methods in objects, it will be displayed as undefined
(3) Deep copy through jQuery's extend method
var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝
(4) lodash function library implements deep copy
let result = _.cloneDeep(test)
(5) Reflect method
// 代理法
function deepClone(obj) {
if (!isObject(obj)) {
throw new Error('obj 不是一个对象!')
}
let isArray = Array.isArray(obj)
let cloneObj = isArray ? [...obj] : {
...obj }
Reflect.ownKeys(cloneObj).forEach(key => {
cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return cloneObj
}
(6) Manually implement deep copy
let obj1 = {
a: 1,
b: 2
}
let obj2 = {
a: obj1.a,
b: obj1.b
}
obj2.a = 3;
alert(obj1.a); // 1
alert(obj2.a); // 3
(7) Use slice to implement a deep copy of an array
// 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝
// 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝
var arr1 = ["1","2","3"];
var arr2 = arr1.slice(0);
arr2[1] = "9";
console.log("数组的原始值:" + arr1 );
console.log("数组的新值:" + arr2 );
(8) Use concat to implement a deep copy of an array
// 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝
var arr1 = ["1","2","3"];
var arr2 = arr1.concat();
arr2[1] = "9";
console.log("数组的原始值:" + arr1 );
console.log("数组的新值:" + arr2 );
// 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝
var arr1 = [{
a:1},{
b:2},{
c:3}];
var arr2 = arr1.concat();
arr2[0].a = "9";
console.log("数组的原始值:" + arr1[0].a ); // 数组的原始值:9
console.log("数组的新值:" + arr2[0].a ); // 数组的新值:9
(9) Use var newObj = Object.create(oldObj) directly to achieve the effect of deep copy.
function deepClone(initalObj, finalObj) {
var obj = finalObj || {
};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
} else {
obj[i] = prop;
}
}
return obj;
}
(10) Deep copy using spread operator
// 当value是基本数据类型,比如String,Number,Boolean时,是可以使用拓展运算符进行深拷贝的
// 当value是引用类型的值,比如Object,Array,引用类型进行深拷贝也只是拷贝了引用地址,所以属于浅拷贝
var car = {
brand: "BMW", price: "380000", length: "5米"}
var car1 = {
...car, price: "500000" }
console.log(car1); // { brand: "BMW", price: "500000", length: "5米" }
console.log(car); // { brand: "BMW", price: "380000", length: "5米" }
(11) If the value of the object is a basic type, Object.assign can also be used to achieve deep copy, but it must be assigned to an empty object
var obj = {
a: 1,
b: 2
}
var obj1 = Object.assign({
}, obj); // obj赋值给一个空{}
obj1.a = 3;
console.log(obj.a);// 1
Refer to the article
for an in-depth understanding
of the difference and implementation of js shallow copy and deep copy of js object reference