JSプロトタイプの属性設定とシールドについて考えてみませんか?

テキストを入力する前に、次の 2 つの質問に答えてみましょう。

質問1:

      let obj = {
         name: "ikun",
      };
      
      let obj1 = {
        fun: "xiaoheizi",
      };

      Object.setPrototypeOf(obj1, obj);
      obj1.name = "cai";
      console.log(obj1);


/*输出结果为:
{fun: 'xiaoheizi', name: 'cai'}
*/

質問2:

      let obj = {
        // name: "ikun",
      };

      Object.defineProperty(obj, "name", {
        writable: false,
        value: "ikun",
      });

      let obj1 = {
        fun: "xiaoheizi",
      };

      Object.setPrototypeOf(obj1, obj);
      obj1.name = "cai";
      console.log(obj1);

//{fun: 'xiaoheizi'}

なぜ?なぜこれが起こるのですか? 勉強を続けましょう:

属性の設定とマスキング

オブジェクトにプロパティを設定することは、新しいプロパティを追加したり、既存のプロパティの値を変更したりするだけではありません。それでは、プロセス全体を見ていきましょう。

 myObject.foo =" bar ";
  1. my0object オブジェクトに foo という名前の通常のデータ アクセス プロパティが含まれている場合、この割り当てステートメントは既存のプロパティ値のみを変更します。
  2. foo が my0object に直接存在しない場合、[[ Get ]] 操作と同様に、[[ Prototype ]] チェーンがトラバースされます。
  3. プロトタイプ チェーンに foo が見つからない場合、foo は my0object に直接追加されます。

ただし、割り当てステートメント myObject . foo = " bar " は、
foo がプロトタイプ チェーンの上位に存在する場合、多少異なる動作をします (おそらく予期せず)。
それについては後で説明します。

プロパティ名 foo が my0bject と my0bject の [[ Prototype ]] チェーンの両方にある場合、マスキングが発生します。myObject.foo は常にプロトタイプ チェーンの最下位の foo プロパティを選択するため、my0object に含まれる foo プロパティは、プロトタイプ チェーンの上位にあるすべての foo プロパティを隠します。

シールドは私たちが思っているよりも複雑です。myObject.foo="bar" のときに foo が myObject に直接存在せず、プロトタイプ チェーンの上位層に存在する場合に発生する 3 つの状況を分析してみましょう。

  1. [[ Prototype ]] チェーンの上位層に foo という名前の通常のデータ アクセス プロパティがあり、それが読み取り専用 (書き込み可能: false) としてマークされていない場合、foo という名前の新しいプロパティが myObject に直接追加されます。 、これはシールド プロパティです。
  2. [[ Prototype ]] チェーンに foo が存在するが、読み取り専用 ( writable : false ) としてマークされている場合、my0object で既存のプロパティを変更したり、シールドされたプロパティを作成したりすることはできません。厳密モードで実行すると、コードはエラーをスローします。それ以外の場合、この割り当てステートメントは無視されます。つまり、シールドは発生しません。
  3. [[ Prototype ]] チェーンに foo が存在し、それが seter である場合、seter を呼び出す必要があります。foo は myObject に追加 (またはシャドウイング) されず、foo セッターも再定義されません。

ほとんどの開発者は、[[ Prototype ]] チェーンの既存のプロパティ ([[ Put ]]) に値を割り当てると、ブロックが確実にトリガーされると想定していますが、ご覧のとおり、3 つのケース (第一種)はこんな感じです。

2 番目と 3 番目のケースで foo もマスクしたい場合は、= 演算子を使用してキーを割り当てることはできませんが、Object.defineProperty(...) を使用して foo を myObject に追加します。 

2 番目のケースはおそらく最も驚くべきものです。読み取り専用のプロパティは、[[ Prototype ]] ダウンチェーンが同じ名前のプロパティを暗黙的に作成 (シールド) するのを防ぎます。これは主にクラスのプロパティの継承をシミュレートするためのもの. プロトタイプチェーンの上位層にある foo を親クラスのプロパティと見なすことができ, myObject に継承 (コピー) されます. myObject も読み取り専用なので作成できません。ただし、同様の継承コピーは実際には発生しないことに注意することが重要です。

他のオブジェクトには読み取り専用の foo があるため、 myObject オブジェクトに foo プロパティを持たないのは少し奇妙に思えます。さらに奇妙なのは、この制限が = 割り当てにのみ存在し、 Object.defineProperty を使用しても影響を受けないことです。私たちは開発するときに注意を払う必要があります。

おすすめ

転載: blog.csdn.net/m0_65335111/article/details/127460207