13

Douglas Crockfords Object.create メソッドの特殊性に遭遇しました。誰かが説明できることを願っています:

オブジェクト リテラル表記を使用してオブジェクト (たとえば「person」) を作成する場合は、Object.create を使用して新しいオブジェクト (たとえば「anotherPerson」) を作成します。これは、最初の「person」オブジェクトからメソッドとプロパティを継承します。

次に、2 番目のオブジェクト「anotherPerson」の名前の値を変更すると、最初の「person」オブジェクトの名前の値も変更されます。

これは、プロパティがネストされている場合にのみ発生します。このコードは、私が何を意味するかを理解できるはずです。

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'

ネストせずに名前の値を保存した場合、この奇妙な動作は発生しません-たとえば

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

この入れ子の問題は、コンストラクター関数と「new」キーワードを使用した従来のスタイルの継承を使用する場合には発生しないようです。

なぜこれが起こるのか誰かが説明できれば、私はとても感謝しています!?

4

3 に答える 3

20

これは、 がオブジェクトであり、元のオブジェクトanotherPerson.nameのプロトタイプ チェーンの上位に格納されているために発生します。person

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

nameこれを回避するには、新しく作成されたオブジェクトのプロパティに新しいオブジェクトを割り当てます。

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

anotherPerson.name = {
  first: 'Stephen',
  last: 'Merchant'
};
于 2010-07-07T00:23:13.693 に答える
2

問題は、Object.create がディープ コピーではなくシャロー コピーのみを行うため、person.name と anotherPerson.name の両方が同じ Object インスタンスを指していることです。

編集済み

それperson.name === anotherPerson.nameは本当ですが、なぜこれが本当なのかについての私の説明は正しくありません。正しい説明については、@CMS の回答を参照してください。

于 2010-07-07T00:23:02.100 に答える
1

属性がコピーされない理由はname、JavaScript のオブジェクト リテラルが常に参照であるためです。したがって、参照が (その内容ではなく) コピーされます。プロトタイプ チェーンの奥深くにあるためでも、浅いコピーを行っているためでもありません。 .

于 2010-07-07T00:46:55.700 に答える