8
var person = { name :"dummy", personal_details: { age : 22, country : "USA" } };

var bob = Object.create(person);

bob.name = "bob";
bob.personal_details.age = 23;


console.log(bob.personal_details === person.personal_details);
// true : since it does not shadow object of prototype object

console.log(bob.name  === person.name);
// false : since it shadows name

////now
bob.personal_details  = {a:1};
console.log(bob.personal_details === person.personal_details); 

//間違い

オブジェクトbobがpersonの「 name」プロパティをオーバーライドしようとすると、bob 自体でシャドウされます。

しかし、personal_detailsの場合、同じルールに違反しています。

なぜそうなのか知りたいです??

jsbin へのリンクは次のとおりです: http://jsbin.com/asuzev/1/edit

4

3 に答える 3

14

何が起こっているかは、いくつかの例で非常に簡単に説明できます。

プロトタイプチェーンを介したpersonal_detailsへのアクセス

var person = { name :"dummy", personal_details: { age : 22, country : "USA" } }
var bob = Object.create(person)

bob.name = "bob"
bob.personal_details.age = 23

次のような出力:

console.log( bob );
/// { name :"bob", personal_details: { age : 23, country : "USA" } }

console.log( person )
/// { name :"dummy", personal_details: { age : 23, country : "USA" } }

23歳がpersonオブジェクトに設定され、bobのプロトタイプチェーンを介しbecause bob.personal_detailsて直接参照されます。person.personal_detailsオブジェクト構造を下に移動すると、オブジェクトを直接操作しperson.personal_detailsます。


プロトタイプ化されたプロパティをローカルプロパティでオーバーライドする

ただし、bobのpersonal_detailsプロパティを別のオブジェクトでオーバーライドすると、そのプロトタイプリンクはよりローカルなプロパティによってオーバーライドされます。

bob.personal_details = { a: 123 }

これで、出力は次のようになります。

console.log( bob );
/// { name :"bob", personal_details: { a : 123 } }

console.log( person )
/// { name :"dummy", personal_details: { age : 23, country : "USA" } }

bob.personal_detailsしたがって、これからアクセスすることで、人{ a: 123 }の元の{ age : 23, country : "USA" }オブジェクトではなく、オブジェクトを参照していることになります。bob加えられたすべての変更はそのオブジェクトで発生し、基本的にはオブジェクトとは関係ありませんperson


プロトタイプチェーン

物事を面白くするために、これを行うと、上記のすべての後に何が起こると思いますか?

delete bob.personal_details

person.personal_details(追加したローカルプロパティを削除したため)への元のプロトタイプリンクを復活させることになり、コンソールログに次のように表示されます。

console.log( bob );
/// { name :"bob", personal_details: { age : 23, country : "USA" } }

基本的に、JavaScriptエンジンは、各プロトタイプオブジェクトで要求しているプロパティまたはメソッドが見つかるまで、プロトタイプチェーンに沿って戻ります。アイテムがチェーンのさらに上に設定されると、後で他のアイテムをオーバーライドすることを意味します。

さて、別の質問ですが、次のことをもう一度実行するとどうなりますか?

delete bob.personal_details

何もありません。bobに割り当てられた実際のプロパティはもうありませんpersonal_detailsdelete現在のオブジェクトでのみ機能し、プロトタイプチェーンをたどることはありません。


別の見方

プロトタイプチェーンがどのように機能するかを確認する別の方法は、基本的にオブジェクトのスタックを想像することです。JavaScriptが特定のプロパティまたはメソッドをスキャンすると、次の構造を介して下向きに読み取られます。

bob :          {  }
  person :     { name: 'dummy', personal_details: { age: 22 } }
    Object :   { toString: function(){ return '[Object object]'; } }

例として、にアクセスしたいとしますbob.toString。は、ほぼすべての基本プロトタイプであるtoStringJavaScriptの基本オブジェクトに存在するメソッドです。Objectインタプリタがオブジェクトの特定のメソッドまたはプロパティの読み取り要求を受け取ると、次の一連のイベントに従います。

  1. bobと呼ばれるプロパティがありますtoStringか?いいえ。
  2. bob.__proto__つまりperson、というプロパティがありますtoStringか?いいえ。
  3. bob.__proto__.__proto__つまりObject、というプロパティがありますtoStringか?はい
  4. 参照を返すfunction(){ return '[Object object]'; }

ポイント4に達すると、インタプリタはtoStringObjectで見つかったメソッドへの参照を返します。未定義Objectのプロパティのエラーでプロパティが見つからなかった場合は、おそらく発生している可能性があります(チェーンの最後であるため)。

さて、前の例を見て、今度はtoStringメソッドを定義するとしますbob-そう:

bob :          { toString: function(){ return '[Bob]'; } }
  person :     { name: 'dummy', personal_details: { age: 22 } }
    Object :   { toString: function(){ return '[Object object]'; } }

もう一度bobのメソッドを読み取りアクセスしようとするとtoString、今度は次のようになります。

  1. bobと呼ばれるプロパティがありますtoStringか?はい。

プロセスは最初のハードルで停止し、toStringbobからメソッドを返します。これは、ではなくbob.toString()戻ることを意味します。[Bob][Object object]

Phant0mによって簡潔に述べられているように、オブジェクトへの書き込み要求は別のパスをたどり、プロトタイプチェーンをたどることはありません。これを理解することは、読み取りと書き込み要求の違いを理解することです。

bob.toString                   --- is a read request
bob.toString = function(){}    --- is a write request
bob.personal_details           --- is a read request
bob.personal_details = {}      --- is a write request
bob.personal_details.age = 123 --- is a read request, then a write request.

最後の項目は混乱を引き起こしている項目です。そして、プロセスは次のルートに従います。

  1. bobと呼ばれるプロパティがありますpersonal_detailsか?いいえ。
  2. personと呼ばれるプロパティがありますpersonal_detailsか?はい。
  3. { age: 22 }メモリ内のどこかにフローティングで保存されている参照を返します。

オブジェクトのナビゲーションまたは割り当ての各部分がプロパティまたはメソッドの新しいリクエストであるため、新しいプロセスが開始されます。これで、personal_detailsオブジェクトを書き込み要求に切り替えることができます。これは、左側のプロパティまたは変数が=等しい側を持っていたため、常に割り当てであるためです。

  1. オブジェクト123のプロパティに値を書き込みますage{ age: 22 }

したがって、元のリクエストは次のように表示されます。

(bob.personal_details)            --- read
    (personal_details.age = 123)  --- write

bobプロセスの独自のプロパティを所有していた場合personal_detailsは同じですが、書き込まれるターゲットオブジェクトは異なります。


そして最後に...

あなたの質問の線に沿って入れてください:

プロトタイプオブジェクトのプロパティがREAD_ONLYとして扱われることを理解するのは困難ですが、プロパティがオブジェクトである場合は、そのプロパティを取得して、そのプロパティを自由に変更できます。私の理解は正しいですか?

プロトタイプ化されたプロパティは一見読み取り専用ですが、それらを継承しているオブジェクトのプロパティとして直接アクセスされた場合にのみ、これらのプロパティは実際には継承オブジェクトにまったく存在しないためです。プロトタイプオブジェクト自体に移動すると、それがまさに通常のオブジェクトであるため、通常のオブジェクト(読み取りと書き込みを含む)と同じように扱うことができます。最初は混乱するかもしれませんが、これは性質またはプロトタイプの継承であり、作業しているプロパティにアクセスする方法がすべてです。

于 2013-01-17T13:20:56.450 に答える
3

以下の図が十分に明確であることを願っていますが、何が起こっているのかを簡単に説明しようと思います。

で新しいオブジェクトをObject.create作成するときは、メソッドの最初の引数をプロトタイプでオブジェクトを作成しますcreate。したがってbob、オブジェクトを指すプロトタイプを使用して作成しpersonます。のすべてのプロパティには、そのプロトタイプへの参照を通じてpersonアクセスできます。bob

次の写真では、bobの名前を変更します。これで、新しい名前または名前bobを作成するだけで済みます(これで、インタープリターはプロパティを探すときにプロトタイプチェーンをチェックせず、bobにそのようなプロパティがあることが直接わかります)。slotpropertybobnamename

3つ目では、同じオブジェクトであるため、bob.personal_details.ageに影響を与える変更を行います。person.personal_details.age

最後に、プロパティを設定しましたpersonal_details。これでbobスロットpersonal_detailsができました。これはプロトタイププロパティではなく、別のオブジェクト(匿名オブジェクト)への参照です。

ここに画像の説明を入力してください

于 2013-01-17T13:16:18.310 に答える
3

2 番目のケースでは のプロパティに割り当てないbobので、どうすればそれをオーバーライドできますか?

の場合はbob.name = "bob"、ボブ自身のname プロパティをバインドします。

2 番目のケースでは、そうではありませんpersonal_detailsプロトタイプを介して、ボブのプロパティにアクセスします。次に、そのオブジェクトのプロパティに割り当てると、その時点までにすべての接続bobが失われます。

次のように考えてください。

bob.personal_details.age = 23;
// equivalent
expr = bob.personal_details;
expr.age = 23; // As you can see, there's no assignment to bob

ケースが全く違うのでルール違反にはなりません。

于 2013-01-17T12:39:09.607 に答える