Asignación de referencias de objetos javascript y copia superficial y copia profunda

En primer lugar, la asignación de referencia del objeto.

1. Tipos de datos en js

基本类型

  • número
  • cadena (cadena)
  • booleano
  • nulo (nulo)
  • indefinido
  • símbolo (símbolo, nuevo en ES6)

引用类型

  • objeto
Para tipos primitivos, la asignación (=) es una copia del valor y la comparación (===) es el valor real
Para los tipos de referencia (Array también es un objeto), la asignación (=) es una copia de la dirección de referencia y la comparación (===) es la dirección de referencia.

2. Caso 1

const a = '哈哈'
const b = '哈哈'
console.log(a === b) // true

const c = {
    
    }
const d = {
    
    }
console.log(c === d) // false

anotación:

1.a和b是字符串,比较的是值,完全相等

2.c和d是对象,比较的是引用地址,c和d都是一个新对象,分别指向不同的地址,所以不相等
inserte la descripción de la imagen aquí

3. Caso 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

anotación:
1.a是对象,b=a是将a的引用地址赋值给b
2.a和b都指向与同一个对象,修改这个对象,a和b都会变化
inserte la descripción de la imagen aquí

3. Caso 3

let a = {
    
     z: 5 }
let b = a
b = {
    
    z: 6}
console.log(a.z) // 5
console.log(a === b) // false

anotación:
1.a是对象,b=a是将a的引用地址赋值给b
2.b = {z: 6}新对象赋值给b,切断了a和b的联系,分别指向于不同的对象
inserte la descripción de la imagen aquí

4. Caso 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

anotación:
1.b = {...a}中,z是基本类型直接拷贝值,y和w是对象,是引用地址的拷贝
2.y是只操作属性,连接不会断开,w操作了本身,生产了一个新对象,连接断开(参考下面的总结)
inserte la descripción de la imagen aquí

5. Resumen: (la esencia)

1、只操作(修改,删除,添加)对象的属性,不会与之前对象断开连接(案例二)

2、直接操作对象本身,也就是最外层,会和之前的对象断开连接(案例三)

3、数组也是对象

2. Copia superficial y copia profunda

1. Diferencias y Conceptos

浅拷贝和深拷贝都只针对于像Object, Array这样的复杂对象

1),浅拷贝

Si el elemento de datos es de tipo básico, se hará una copia sin afectarse entre sí, y si es un objeto o un array, sólo se copiará la referencia del objeto y del array, por lo que no importa si modificamos el matriz antigua o nueva, ambas cambiarán. Esto se denomina copia superficial

2),深拷贝

La copia profunda se refiere a una copia completa de un objeto. Incluso si los objetos están anidados, los dos están separados entre sí. La modificación de las propiedades de un objeto no afectará al otro.

3),区别

Diferencia: la copia superficial solo copia los atributos de primer nivel del objeto, mientras que la copia profunda puede copiar recursivamente los atributos del objeto

2. Si se trata de un tipo de datos básico, el nombre y el valor se almacenarán en la memoria de la pila

var a = 1;
b = a; // 栈内存会开辟一个新的内存空间,此时b和a都是相互独立的
b = 2;
console.log(a); // 1

Por supuesto, esta no es una copia profunda, porque la copia profunda en sí misma es solo para datos de tipos de objetos más complejos.

3. Si es un tipo de datos de referencia, el nombre se almacena en la memoria de pila y el valor se almacena en la memoria de pila, pero la memoria de pila proporcionará una dirección de referencia que apunta al valor en la memoria de pila.

Por ejemplo copia superficial:

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

inserte la descripción de la imagen aquí
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了

inserte la descripción de la imagen aquí

4. Cómo implementar una copia superficial

(1) para... en solo bucles la primera capa

// 只复制第一层的浅拷贝
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

inserte la descripción de la imagen aquí
(2) método Object.assign

var obj = {
    
    
    a: 1,
    b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a) // 3

(3) Uso directo = asignación

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]

Debido a que la operación es una matriz, es un tipo de referencia, por lo que a, b apuntan a la misma dirección, cambiando uno, el otro también se ve afectado
inserte la descripción de la imagen aquí
(4) Use la biblioteca de funciones lodash para implementar

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

inserte la descripción de la imagen aquí

5. El método de implementación de deep copy

(1) Utilice la recursividad para copiar todos los atributos jerárquicos

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

inserte la descripción de la imagen aquí
(2) Copia profunda a través del objeto JSON

function deepClone2(obj) {
    
    
  var _obj = JSON.stringify(obj),
    objClone = JSON.parse(_obj);
  return objClone;
}

Desventajas: no se puede implementar una copia profunda de los métodos en los objetos, se mostrará como indefinido

(3) Copia profunda a través del método de extensión de jQuery

var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝

(4) la biblioteca de funciones lodash implementa una copia profunda

let result = _.cloneDeep(test)

(5) Método de reflexión

// 代理法
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) Implementar manualmente copia profunda

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 para implementar una copia profunda de una matriz

// 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝
// 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝
var arr1 = ["1","2","3"]; 
var arr2 = arr1.slice(0);
arr2[1] = "9";
console.log("数组的原始值:" + arr1 );
console.log("数组的新值:" + arr2 );

inserte la descripción de la imagen aquí
(8) Use concat para implementar una copia profunda de una matriz

// 当数组里面的值是基本数据类型,比如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

inserte la descripción de la imagen aquí
(9) Use var newObj = Object.create(oldObj) directamente para lograr el efecto de copia profunda.

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) Copia profunda usando el operador de extensión

// 当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) Si el valor del objeto es un tipo básico, Object.assign también se puede usar para lograr una copia profunda, pero debe asignarse a un objeto vacío

var obj = {
    
    
    a: 1,
    b: 2
}
var obj1 = Object.assign({
    
    }, obj); // obj赋值给一个空{}
obj1.a = 3;
console.log(obj.a)// 1

Consulte el artículo
para obtener una comprensión profunda
de la diferencia y la implementación de la copia superficial js y la copia profunda de la referencia del objeto js

Supongo que te gusta

Origin blog.csdn.net/qq_41880073/article/details/123720584
Recomendado
Clasificación