es5 インスタンス __proto__ (プロトタイプ チェーン) プロトタイプ (プロトタイプ オブジェクト) {コンストラクター: コンストラクター}

この写真を見ると、わかりにくくなり始めているので、この写真のコンテキストを基本的に理解するために、プロトタイプの基本的な内容を簡単に確認します。
ここに画像の説明を挿入します
まず基本的な概念を紹介しましょう。

function Person() {
    
    }

Person.prototype.name = 'KK';

let person1 = new Person();

上の例では、

person はコンストラクター(関数を構築して呼び出すもので、以下便宜上 と呼びます构造函数)と呼ばれます。 person.prototype は
person の person1原型对象
とも呼ばれます实例
TL;DR.
コンストラクターにはデフォルトでプロトタイプ属性が含まれ、その値はプロトタイプ オブジェクト、つまり Parent.prototype = Parent.prototype を指します。デフォルトでは、
constructor.Prototype object.constructor = constructionor Parent.prototype.constructor =親。しかし、明確な書き換えがある場合には、この方向ではない可能性があります。
Instance.proto =constructor.Prototype object person.proto = Parent.prototypeインスタンスとコンストラクターのプロトタイプ オブジェクトの間には直接的な接続がありますが、インスタンスとコンストラクターの間には直接的な接続はありません

プロトタイプオブジェクト

関数を作成するとき、Function のコンストラクターは、継承された特性を格納するオブジェクト プロパティ プロトタイプにバインドされた関数オブジェクトを生成します。Function のコンストラクターは、関数オブジェクトを生成するときに、同様のコードを実行します。

this.prototype = {
    
     constructor : this}

この属性プロトタイプの値は、デフォルトでは、コンストラクター属性を含むオブジェクトのみが取得され、残りのメソッドは Object から継承されます。このオブジェクトは、コンストラクターを呼び出して作成されたオブジェクトのプロトタイプです。プロトタイプ オブジェクト プロトタイプを使用する利点は、プロトタイプに定義されているプロパティとメソッドをオブジェクトのインスタンスで共有できることです。コンストラクター内のオブジェクト インスタンスに最初に割り当てられた値は、そのプロトタイプに直接割り当てることができます。

function Parent() {
    
    }

// 定义在 Parent.prototype 的值,可以被该对象实例共享。
Parent.prototype.name = 'KK';

Parent.prototype.sayHi = function () {
    
    
  console.log('hi,', this.name);
};

// Parent 对象的实例 person1, person2
let person1 = new Parent();
let person2 = new Parent();

person1.sayHi(); // hi, KK
person2.sayHi(); // hi, KK

プロトタイプに含まれるコンストラクターは、それに関連付けられたコンストラクターを指します。以下の図に示すように、Parent のプロトタイプが Parent.prototype (ナンセンスのように思えます) を指しており、Parent.prototype のコンストラクターが Parent を指していることがわかります。言い換えれば、コンストラクターとコンストラクターのプロトタイプ オブジェクトのコンストラクターとの間で循環参照が形成されます。

ここに画像の説明を挿入します
ここに画像の説明を挿入します

プロト| [[プロトタイプ]]

始める前に、new 演算子を確認しましょう。Object.create() メソッドは、既存のオブジェクトを使用して、新しく作成されたオブジェクトのプロトを提供する新しいオブジェクトを作成します。このステップにより、インスタンス オブジェクトとコンストラクター関数 func のプロトタイプ オブジェクトがリンクされ、プロトタイプ オブジェクトで定義されたメソッドやプロパティへのアクセスが容易になります。

function myNew(func, ...args) {
    
    

		// 1. 在内存中创建一个新对象
    const obj = Object.create()
		
		// 2. 在这个新对象内部的 [[ prototype ]] 特性被赋值为构造函数的 prototype 属性
    obj.__proto__ = func.prototype
		
		// 3. 构造函数内部的 this 被赋值为这个新对象
		// 执行构造函数内部代码
    let result = func.apply(obj, args)
    
		// 4. 如果构造函数返回一个非空对象,则返回该对象,都则则返回刚刚创建的新对象
		return result instanceof Object ? result : obj
}

その中で、ステップ 1.2 を組み合わせると const obj = Object.create(func.prototype) となり、Object.create() メソッドは新しいオブジェクトを作成し、新しいオブジェクトのプロトを指定されたオブジェクトに関連付けます。

新しい演算子を確認した後、先ほどの例、parent によって作成されたオブジェクト インスタンスである person1 と person2 に進みましょう。コンストラクターを通じて新しいインスタンスを作成するたびに、インスタンスはprotoを通じてコン​​ストラクターのプロトタイプ オブジェクトと、以下の図の最初の部分にリンクされます。

function Parent() {
    
    }

// Parent 对象的实例 person1, person2
let person1 = new Parent();
let person2 = new Parent();

しかし、図からわかるように、オブジェクトインスタンス person のproto は、そのコンストラクタのプロトタイプオブジェクト Parent.prototype を直接指していることが分かりますが、インスタンスとプロトタイプオブジェクトの関係は、実際には参照関係であり、再帰関係ではありません。プロトタイプ オブジェクトのコピーを保存します。同時に、オブジェクト インスタンスとコンストラクターの間に直接の関係がないこともわかります。

ここに画像の説明を挿入します

console.log(person1.__proto__ === Parent.prototype); // true
console.log(person1.__proto__.constructor === Parent); // true

console.log(person1 instanceof Parent)

プロトタイプチェーンの検索

プロトタイプチェーンに沿った検索についてよく言及しますが、プロトタイプチェーン検索とは何ですか? プロトタイプチェーンを検索するにはどうすればよいですか?

オブジェクトのデフォルトの取得操作では、最初にオブジェクト インスタンスから検索が開始されます。見つかった場合は、指定されたオブジェクト属性値が返されます。それ以外の場合、検索はプロトタイプ オブジェクトに入り、プロトタイプ オブジェクトの検索を開始し、次に対応する値を返します。前のセクションで示したように、person.name と入力すると、最初に person を入力して検索することがわかります。検索がうまくいかない場合は、Parent.prototype と入力して再検索します。これにより、プロトタイプが複数のオブジェクト インスタンス間でプロパティとメソッドを共有できるようになります。

function Parent() {
    
    
  name: 'Parent';
}

Parent.prototype.nickname = 'KK';

Parent.prototype.sayHi = function () {
    
    
  console.log(this.nickname);
};

let person1 = new Parent();

person1.nickname = 'person1';
person1.sayHi();

console.log(person1.nickname); // person1 

プロトタイプ オブジェクトと同じ名前のプロパティをインスタンス オブジェクトに追加すると、そのプロパティ値がインスタンスに作成され、インスタンス オブジェクトの同じ名前のプロパティによってプロトタイプ オブジェクトの元のプロパティが隠蔽されます。いわゆるマスキングは、プロトタイプ オブジェクト上の同じ名前のプロパティへのアクセスがブロックされるだけで、変更されません。delete を使用する場合のみ、インスタンス上のこの属性を完全に削除し、プロトタイプ オブジェクト上の同じ名前の属性へのアクセスを復元できます。そうしないと、インスタンス上の同名のプロパティが null に変更されても、プロトタイプ オブジェクト上の同名のプロパティとの接続は復元できません。

属性「オーバーライド」またはシャドウ
もちろん、このオブジェクトのプロパティを設定するには一定のルールがあり、いわゆるシールドは想像よりも複雑です。インスタンス オブジェクトに同じ名前の属性を設定するプロセスをいくつかの状況に分けて分析できます。

プロパティがプロトタイプ オブジェクトに存在しない場合は、直接設定できます。
プロパティがプロトタイプ オブジェクトに存在する場合: プロパティは
通常のデータに対してのみアクセスされ、writable:false が設定されていない場合、同じ名前のプロパティが設定されます。インスタンス オブジェクトに追加され、元のプロトタイプ オブジェクトの同じ名前のプロパティへのアクセスがシールドされます。writable
:false が設定され、プロパティが読み取り専用としてマークされている場合、同じ名前のプロパティをインスタンス オブジェクトに設定する操作が行われます。インスタンス オブジェクトがインターセプトされます。このコピー操作は、厳密モードではエラーが報告され、非厳密モードではデフォルトで無視されます。つまり、プロトタイプ オブジェクトの同じ名前のプロパティにシャドウ効果を与えることは不可能です。
注意: プロトタイプ オブジェクトに読み取り専用属性がある限り、同じ名前の属性を割り当てることができないのは少し混乱するようです。ただし、この制限は = のコピー操作にのみ存在します。Object.defineProperty() を直接使用する場合は影響を受けず、インスタンス オブジェクトを直接コピーすることは可能です。

プロトタイプ オブジェクトの同じ名前のプロパティにセッター セットがある場合、そのセッターが呼び出され、同じ名前のプロパティを設定するアクションがそのセッターに適用されます。また、プロトタイプ オブジェクトに対するブロック効果もありません。プロトタイプオブジェクトの同名のプロパティ。

in および hasOwnProperty 属性ソース

このようなコードがあると仮定すると、通常のコピーによって person プロトタイプ オブジェクトの Nickname 属性をマスクしていることがわかります。プロパティがインスタンス上にあるかプロトタイプ上にあるかに関係なく、オブジェクトを通じてオブジェクト プロパティにアクセスできる場合に in 演算子が使用されている限り、演算結果は true を返します。

function Parent() {
    
    
  nickname: 'Parent';
}

Parent.prototype.nickname = 'KK';

let person1 = new Parent();
let person2 = new Parent();

person1.nickname = 'person1';

console.log('nickname' in person1); // true
console.log('nickname' in person2); // true

属性アクセス、つまり属性の取得操作では、ルート オブジェクトが見つかるか到達するまで、プロトタイプ チェーンに沿って検索されることがわかっています。したがって、このプロパティがインスタンス オブジェクト上にあるかプロトタイプ オブジェクト上にあるかを判断する必要がある場合は、 hasOwnProperty() メソッドを使用できます。このメソッドは、特定のプロパティがインスタンス オブジェクト上にあるかプロトタイプ オブジェクト上にあるかを判断するために使用できます。次のように、プロパティがオブジェクトに対して呼び出されたときに true を返します。

console.log(person1.hasOwnProperty('nickname')); // true
console.log(person2.hasOwnProperty('nickname')); // false

前述の in および hasOwnProperty と組み合わせると、プロトタイプ オブジェクトのプロパティのみが必要かどうかをどのように判断できるでしょうか。in と hasOwnProperty の特性を組み合わせた hasPrototypeProperty メソッドを作成できます。

function hasPrototypeProperty(obj, propertyKey) {
    
    
  return !obj.hasOwnProperty(propertyKey) && propertyKey in obj;
}

物件取得

オブジェクト属性のトラバーサルでは、for-in と Object.keys() を使用できますが、この 2 つの間には特定の違いがあります。

for-in は
for で in 演算子を使用し、インスタンス プロパティとプロトタイプ オブジェクトのプロパティを含む、オブジェクトを通じてアクセスでき、列挙可能なすべてのプロパティが返されます。Enumberable:false を設定すると、オブジェクトは列挙不可能なプロパティになり、ループで返されなくなります。注意すべき点の 1 つは、プロトタイプ オブジェクトの列挙不可能なプロパティをカバーするためにインスタンス上で同じ名前のプロパティを定義する場合、明示的に定義されていない同じ名前のこのプロパティは、インスタンス上で列挙不可能なプロパティとして定義されることです。オブジェクトを返すことができます (つまり、列挙可能ではありません)。属性を上げてもインスタンスの属性には影響しません。

Object.keys()
オブジェクト上のすべての列挙可能なプロパティを取得したい場合は、Object.keys() メソッドを使用できます。このメソッドは、オブジェクトをパラメータとして受け入れ、オブジェクト上のすべての列挙可能なプロパティ名の配列を Contains なしで返します。プロトタイプ オブジェクトのプロパティ。

このメソッドは、for-in + hasOwnProperty の組み合わせとして理解でき、プロトタイプ チェーンに沿って検索せずにオブジェクトのプロパティのみを返します。

Object.getOwnPropertyNames()
列挙可能かどうかに関係なく、すべてのインスタンス プロパティを一覧表示する場合は、Object.getOwnPropertyNames() を使用できます。ただし、このメソッドの戻り結果には列挙できない属性が含まれることに注意してください。プロトタイプ オブジェクトでこのメソッドを使用すると、メソッドはコンストラクターを返します。

ES6 に Symbol シンボル タイプが表示されると、対応する Object.getOwnPropertySymbols() が表示されます。このメソッドは実際には getOwnPropertyNames に似ていますが、このメソッドはシンボル タイプ Symbol 専用です。

これらのメソッドの場合、for-in および Object.keys() によって返される列挙順序は不確実であり、具体的な実装は対応する JavaScript エンジンの実装に依存します。Object.getOwnPropertyNames() または Object.assign() を使用することが確実です。結果は、列挙文字列記号キーの列挙値キー挿入順序に従って返されます。YDKJS に例があります。これを少し拡張して、より明確に確認できるようにします。

let sym1 = Symbol('sym1')
let sym2 = Symbol('sym2')
let sym3 = Symbol('sym3')

let obj = {
    
    
  1: 1,
  [sym3]: 'sym3',
  [sym1]: 'sym1',
  second: 'second',
  first: 'first',
  0: 0
}

obj[sym2] = 'sym2'
obj[3] = 3
obj.forth = 'forth'
obj.third = 'third'
obj[2] = 2

console.log(Object.getOwnPropertyNames(obj)) // [ '0', '1', '2', '3', 'second', 'first', 'forth', 'third' ]
console.log(Object.getOwnPropertySymbols(obj)) //  [ Symbol(sym3), Symbol(sym1), Symbol(sym2) ]

プロトタイプの判定方法

Object.getPrototypeOf()
Object.getPrototypeOf() メソッドは、指定されたオブジェクトのプロトタイプ (内部 [[Prototype]] プロパティの値) を返します。具体的な使用方法は次のとおりです。

Object.getPrototypeOf(object)

Object.getPrototypeOf(person1); // { name: 'KK', sayHi: [Function (anonymous)] } 

Object.getPrototypeOf(person1) === Parent; // true

Object.prototype.isPrototypeOf()
Object.prototype.isPrototypeOf() メソッドは、オブジェクトが別のオブジェクトのプロトタイプ チェーン上に存在するかどうかをテストするために使用されます。すべてのメソッドが外部に公開されたprotoを実装しているわけではありませんが、 person.prototype を指すリンクが person 内に存在するため、 isPrototypeOf() を通じて Parent.prototype と person の間の関係を判断できます。したがって、結果は true を返します。

Parent.prototype.isPrototypeOf(person1); // true

instanceofinstanceof
は、インスタンスのプロトタイプ チェーンにコンストラクターのプロトタイプが含まれているかどうかを判断するために使用されます。具体的な使用法は、instanceofconstructionFunc です。ただし、インスタンスのプロトタイプを明示的に変更する場合、この方法は適用できない場合があることに注意してください。

person1 instanceof Parent ; // true

この記事では、プロトタイプに関する関連コンテンツを簡単に紹介します 記事冒頭の写真について、今振り返ってみますと、まだ反応が遅いと感じていますが、慎重に検討した結果、リンクと文脈を理解できるようになると思います全体像の。少し休憩して内容を理解してから、新しい記事の章であるプロトタイプ チェーンの継承を開始します。

おすすめ

転載: blog.csdn.net/weiyi47/article/details/132644086