Pregunta

Me he encontrado con una peculiaridad con el método de Douglas Crockfords Object.create la que estoy esperando que alguien podría ser capaz de explicar:

Si creo un objeto - por ejemplo 'persona' - usando la notación literal de objetos a continuación, utilizar Object.create para crear un nuevo objeto - por ejemplo 'anotherPerson' -., Que hereda los métodos y propiedades del objeto inicial 'persona'

Si entonces cambiar los valores de nombre del segundo objeto - 'anotherPerson' -. También cambia el valor del nombre del objeto inicial 'persona'

Esto sólo ocurre cuando las propiedades están anidados, este código debe darle una idea de lo que quiero decir:

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
};

// initiate new 'person' object
var person = {
    name: {
        first: 'Ricky',
        last: 'Gervais'
    },
    talk: function() {
        console.log('my name is ' + this.name.first + ' ' + this.name.last);
    }
}

// create anotherPerson from person.prototype
var anotherPerson = Object.create(person);
// change name of anotherPerson
anotherPerson.name.first = 'Stephen';
anotherPerson.name.last = 'Merchant';

// call talk method of both 'person' and 'anotherPerson' objects
person.talk(); // oddly enough, prints 'Stephen Merchant'
anotherPerson.talk(); // prints 'Stephen Merchant'

Si tuviera que almacenar los valores de nombre y sin anidación entonces este extraño comportamiento no se produce -. Por ejemplo

// initiate new 'person' object
var person = {
    firstName: 'Ricky',
    lastName: 'Gervais',
    talk: function() {
        console.log('my name is ' + this.firstName + ' ' + this.lastName);
    }
}

// create anotherPerson from person.prototype
var anotherPerson = Object.create(person);
// change name of anotherPerson
anotherPerson.firstName = 'Stephen';
anotherPerson.lastName = 'Merchant';

// call talk method of both 'person' and 'anotherPerson' objects
person.talk(); // prints 'Ricky Gervais'
anotherPerson.talk(); // prints 'Stephen Merchant'

Este problema anidación no parece ocurrir cuando se utiliza un estilo clásico de la herencia con una función constructora y la palabra clave 'nuevo'.

Me sería mucho agradecidos si es capaz de explicar por qué se produce este nadie!?

¿Fue útil?

Solución

Eso ocurre porque anotherPerson.name es un objeto y se almacena superior en la cadena de prototipo, en el objeto person original:

//...
var anotherPerson = Object.create(person);
anotherPerson.hasOwnProperty('name'); // false, the name is inherited
person.name === anotherPerson.name; // true, the same object reference

Esto se puede evitar mediante la asignación de un nuevo objeto a la propiedad name del objeto recién creado:

// create anotherPerson from person
var anotherPerson = Object.create(person);

anotherPerson.name = {
  first: 'Stephen',
  last: 'Merchant'
};

Otros consejos

El problema es que Object.create sólo lo hace una copia superficial, no una copia profunda, tan person.name y anotherPerson.name tanto punto a la misma instancia de objeto.

Editado

Si bien es cierto que person.name === anotherPerson.name, mi explicación de por qué esto es cierto no es correcta. Ver @ respuesta de CMS para la explicación correcta.

La razón name el atributo no se copia se debe a que los literales de objetos en JavaScript son siempre referencias, por lo tanto, se copia la referencia (no su contenido) ... por lo que no se debe a que es más profundo en la cadena de prototipo o porque es hacer una copia superficial.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top