He cambiado los ejemplos para darle una mejor demostración de lo que está sucediendo aquí.Demo
Primero creamos un objeto con tres propiedades; Un número, una cadena y un objeto con una propiedad con un valor de cadena.
Luego creamos un segundo objeto a partir del primero usando Object.create()
;
var obj1 = {
num : 1,
str : 'foo',
obj : { less: 'more' }
};
var obj2 = Object.create(obj1);
console.log('[1] obj1:', obj1);
console.log('[1] obj2:', obj2);
"[1] obj1:"
[object Object] {
num: 1,
obj: [object Object] {
less: "more"
},
str: "foo"
}
"[1] obj2:"
[object Object] {
num: 1,
obj: [object Object] {
less: "more"
},
str: "foo"
}
Se ve bien ¿verdad? Tenemos nuestro primer objeto y un segundo objeto copiado.
No tan rápido; Veamos qué sucede cuando cambiamos algunos de los valores en el primer objeto.
obj1.num = 3;
obj1.str = 'bar';
obj1.obj.less = 'less';
console.log('[2] obj1:', obj1);
console.log('[2] obj2:', obj2);
"[2] obj1:"
[object Object] {
num: 3,
obj: [object Object] {
less: "less"
},
str: "bar"
}
"[2] obj2:"
[object Object] {
num: 3,
obj: [object Object] {
less: "less"
},
str: "bar"
}
Ahora, de nuevo tenemos nuestro primer objeto, con los cambios, y una copia de ese objeto. ¿Que esta pasando aqui?
Vamos a verificar si los objetos tienen sus propias propiedades.
for(var prop in obj1) console.log('[3] obj1.hasOwnProperty(' + prop + '): ' + obj1.hasOwnProperty(prop));
for(var prop in obj2) console.log('[3] obj2.hasOwnProperty(' + prop + '): ' + obj2.hasOwnProperty(prop));
"[3] obj1.hasOwnProperty(num): true"
"[3] obj1.hasOwnProperty(str): true"
"[3] obj1.hasOwnProperty(obj): true"
"[3] obj2.hasOwnProperty(num): false"
"[3] obj2.hasOwnProperty(str): false"
"[3] obj2.hasOwnProperty(obj): false"
obj1
tiene todas sus propiedades, al igual que hemos definido, pero obj2
no.
¿Qué sucede cuando cambiamos algunas de las propiedades de obj2
?
obj2.num = 1;
obj2.str = 'baz';
obj2.obj.less = 'more';
console.log('[4] obj1:', obj1);
console.log('[4] obj2:', obj2);
for(var prop in obj1) console.log('[4] obj1.hasOwnProperty(' + prop + '): ' + obj1.hasOwnProperty(prop));
for(var prop in obj2) console.log('[4] obj2.hasOwnProperty(' + prop + '): ' + obj2.hasOwnProperty(prop));
"[4] obj1:"
[object Object] {
num: 3,
obj: [object Object] {
less: "more"
},
str: "bar"
}
"[4] obj2:"
[object Object] {
num: 1,
obj: [object Object] {
less: "more"
},
str: "baz"
}
"[4] obj1.hasOwnProperty(num): true"
"[4] obj1.hasOwnProperty(str): true"
"[4] obj1.hasOwnProperty(obj): true"
"[4] obj2.hasOwnProperty(num): true"
"[4] obj2.hasOwnProperty(str): true"
"[4] obj2.hasOwnProperty(obj): false"
Así, num
y str
cambió el obj2
y no en obj1
al igual que queríamos, pero obj1.obj.less
cambiado cuando no debería tener.
De los controles hasOwnProperty()
podemos ver que, aunque hemos cambiado obj2.obj.less
, no hemos configurado obj2.obj
primero. Esto significa que todavía nos estamos refiriendo al obj1.obj.less
.
Vamos a crear un objeto a partir del obj1.obj
y asignarlo al obj2.obj
y ver si eso nos da lo que estamos buscando.
obj2.obj = Object.create(obj1.obj);
console.log('[5] obj1:', obj1);
console.log('[5] obj2:', obj2);
for(var prop in obj1) console.log('[5] obj1.hasOwnProperty(' + prop + '): ' + obj1.hasOwnProperty(prop));
for(var prop in obj2) console.log('[5] obj2.hasOwnProperty(' + prop + '): ' + obj2.hasOwnProperty(prop));
"[5] obj1:"
[object Object] {
num: 3,
obj: [object Object] {
less: "more"
},
str: "bar"
}
"[5] obj2:"
[object Object] {
num: 1,
obj: [object Object] {
less: "more"
},
str: "baz"
}
"[5] obj1.hasOwnProperty(num): true"
"[5] obj1.hasOwnProperty(str): true"
"[5] obj1.hasOwnProperty(obj): true"
"[5] obj2.hasOwnProperty(num): true"
"[5] obj2.hasOwnProperty(str): true"
"[5] obj2.hasOwnProperty(obj): true"
Eso es bueno, ahora obj2
tiene su propio obj
propiedad. Veamos qué pasa cuando cambiamos obj2.obj.less
ahora.
obj2.obj.less = 'less';
console.log('[6] obj1:', obj1);
console.log('[6] obj2:', obj2);
"[6] obj1:"
[object Object] {
num: 3,
obj: [object Object] {
less: "more"
},
str: "bar"
}
"[6] obj2:"
[object Object] {
num: 1,
obj: [object Object] {
less: "less"
},
str: "baz"
}
Así que lo que todo esto nos dice es que, si la propiedad no ha sido cambiado en el objeto creado, cualquier get
peticiones al objeto creado para que los bienes serán remitidos al objeto original.
La solicitud set
para obj2.obj.less = 'more'
desde el bloque de código anterior requiere primero una solicitud get
para obj2.obj
, que no existe en obj2
en ese punto, por lo que hacia delante para obj1.obj
y a su vez obj1.obj.less
.
Entonces, finalmente, cuando leemos obj2
de nuevo, todavía no hemos establecido obj2.obj
modo que get
solicitud será enviada a obj1.obj
y devolver el ajuste que habíamos cambiado previamente, causando el efecto que el cambio de una propiedad de los objetos segundo objeto el niño parece cambiar ambos, pero realmente solo está cambiando realmente el primero.
Puede usar esta función para devolver un objeto nuevo completamente separado del original recursivamente.
Demo
var obj1 = {
num : 1,
str : 'foo',
obj : { less: 'more' }
};
var obj2 = separateObject(obj1);
function separateObject(obj1) {
var obj2 = Object.create(Object.getPrototypeOf(obj1));
for(var prop in obj1) {
if(typeof obj1[prop] === "object")
obj2[prop] = separateObject(obj1[prop]);
else
obj2[prop] = obj1[prop];
}
return obj2;
}
console.log('[1] obj1:', obj1);
console.log('[1] obj2:', obj2);
for(var prop in obj1) console.log('[1] obj1.hasOwnProperty(' + prop + '): ' + obj1.hasOwnProperty(prop));
for(var prop in obj2) console.log('[1] obj2.hasOwnProperty(' + prop + '): ' + obj2.hasOwnProperty(prop));
"[1] obj1:"
[object Object] {
num: 1,
obj: [object Object] {
less: "more"
},
str: "foo"
}
"[1] obj2:"
[object Object] {
num: 1,
obj: [object Object] {
less: "more"
},
str: "foo"
}
"[1] obj1.hasOwnProperty(num): true"
"[1] obj1.hasOwnProperty(str): true"
"[1] obj1.hasOwnProperty(obj): true"
"[1] obj2.hasOwnProperty(num): true"
"[1] obj2.hasOwnProperty(str): true"
"[1] obj2.hasOwnProperty(obj): true"
Vamos a ver lo que sucede cuando cambiamos algunas variables ahora.
obj1.num = 3;
obj1.str = 'bar';
obj1.obj.less = 'less';
console.log('[2] obj1:', obj1);
console.log('[2] obj2:', obj2);
"[2] obj1:"
[object Object] {
num: 3,
obj: [object Object] {
less: "less"
},
str: "bar"
}
"[2] obj2:"
[object Object] {
num: 1,
obj: [object Object] {
less: "more"
},
str: "foo"
}
Todo funciona exactamente de la manera que se esperaba que lo haga.
relacionados: [JavaScript Object.create - heredar propiedades anidadas] (http://stackoverflow.com/q/3191103/1048572) – Bergi