Reference assignment of javascript objects and shallow copy and 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都是一个新对象,分别指向不同的地址,所以不相等
insert image description here

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都会变化
insert image description here

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的联系,分别指向于不同的对象
insert image description here

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操作了本身,生产了一个新对象,连接断开(参考下面的总结)
insert image description here

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:

insert image description here
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值
insert image description here
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了

insert image description here
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了

insert image description here

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

insert image description here
(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
insert image description here
(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

insert image description here

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);

insert image description here
(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 );

insert image description here
(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

insert image description here
(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

Guess you like

Origin blog.csdn.net/qq_41880073/article/details/123720584