Asignación de referencias de objetos javascript y copia superficial y copia profunda
- En primer lugar, la asignación de referencia del objeto.
- 2. Copia superficial y copia profunda
-
- 1. Diferencias y Conceptos
- 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
- 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.
- 4. Cómo implementar una copia superficial
- 5. El método de implementación de deep copy
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都是一个新对象,分别指向不同的地址,所以不相等
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都会变化
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的联系,分别指向于不同的对象
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操作了本身,生产了一个新对象,连接断开(参考下面的总结)
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:
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了
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
(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
(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
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);
(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 );
(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
(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