2010-07-07 12 views
11

Natknąłem osobliwością metodą Douglas Crockfords Object.create które mam nadzieję, że ktoś może być w stanie wyjaśnić:JavaScript Object.create - dziedziczenie zagnieżdżone właściwości

Jeśli utworzyć obiektu - powiedzieć " osoba "- używając zapisu literalnego obiektu, użyj Object.create, aby utworzyć nowy obiekt - powiedzmy" anotherPerson "- który dziedziczy metody i właściwości z początkowego obiektu" osoba ".

Jeśli następnie zmienię wartości nazwy drugiego obiektu - "anotherPerson" - zmieni on również wartość nazwy początkowego obiektu "person".

Dzieje się tak tylko wtedy, gdy właściwości są zagnieżdżone, kod ten powinien dać wyobrażenie o tym, co to znaczy:

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' 

Gdybym przechowywania wartości nazw bez zagnieżdżania potem to dziwne zachowanie nie występuje - - np

// 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' 

ten gniazdowania problem nie wydaje się występować podczas korzystania klasyczny styl dziedziczenia z funkcji konstruktora i „nowych” słowa kluczowego.

Byłbym bardzo wdzięczny, gdyby ktoś mógł wyjaśnić, dlaczego tak się dzieje !?

+2

możliwy duplikat: [Dziedzictwo prototypowe Crockforda - problemy z obiektami zagnieżdżonymi] (http://stackoverflow.com/q/10131052/1048572) – Bergi

Odpowiedz

18

Dzieje się tak dlatego anotherPerson.name jest obiektem i jest on przechowywany górny do łańcucha prototypów, na oryginalnym person obiektu:

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

Można tego uniknąć poprzez przypisanie nowego obiektu do właściwości nowo name utworzony obiekt:

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

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

Wow, przepełnienie stosu jest bardziej jak komunikator internetowy niż forum! Dzięki za odpowiedź, to ma sens - więc drugi obiekt ma tylko nazwę obiektu przez odniesienie, nie jest on faktycznie kopiowany. Następnie zakładam, że oryginalny obiekt "osoba" oceniłby hasOwnProperty ("name") === true, ponieważ jest to prototyp "anotherPerson". – Richard

+1

Jestem nowy w JavaScript, ale domyślam się, że możesz również użyć: 'anotherPerson.name = Object.create (person.name);' aby nowy obiekt zagnieżdżony dziedziczył ze starego zagnieżdżonego obiektu, jeśli jest to pożądane. –

+0

To już stara odpowiedź, ale wciąż mam na to pytanie. Rozumiem, że nazwa B.name nie istnieje i idzie w górę, aby znaleźć A.name, a więc zastępuje nazwę A.name. Dlaczego jednak w drugim przykładzie nazwa "B.firstName/lastName" istnieje w obiekcie B i nie zastępuje właściwości A? – user2734550

2

Problem polega na tym, że Object.create wykonuje tylko płytką kopię, a nie kopię w formacie deep, więc nazwa_osobowa i nazwa_personelu wskazują na to samo wystąpienie obiektu.

Edited

Chociaż prawdą jest, że person.name === anotherPerson.name, moje wyjaśnienie, dlaczego jest to prawdą jest nieprawidłowy. Zobacz odpowiedź @ CMS na prawidłowe wyjaśnienie.

+2

Prawda, oba wskazują na to samo wystąpienie, ale w rzeczywistości 'Object.create' doesn 't tworzy kopię obiektu w ogóle, po prostu tworzy nowy * pusty obiekt *, który * dziedziczy * z oryginału. – CMS

+0

Dzięki za odpowiedź. Czy znasz jakieś przyzwoite artykuły na płytkiej i głębokiej kopii? – Richard

+0

@CMS, faktycznie 'F.prototype = o;' jest kopią. Kopiuje obiekt i jego właściwości wewnątrz prototypu nowego obiektu ... a powodem, dla którego nie jest kopiowany atrybut 'name', jest fakt, że literały obiektów w JavaScript są zawsze odnośnikami, dlatego odwołanie jest kopiowane (a nie jego treść). ... więc to nie dlatego, że jest głębszy w łańcuchu prototypów lub dlatego, że robi płytką kopię. –

1

powodem atrybut name nie są kopiowane dlatego literały obiektowe w JavaScript są zawsze odniesienia, zatem odniesienie jest kopiowany (nie jego treść) ... więc to nie dlatego, że jest głębiej w łańcuchu prototypów lub dlatego, że robi płytką kopię.

+0

To ma dla mnie sens. Czy nadal jest poprawny? – ryansstack

Powiązane problemy