プロトタイプ、__proto__、prototype がよくわからないので、今日は少し勉強します。
プロトタイプと __proto__ は両方ともプロトタイプ オブジェクトを指します。
__proto__:オブジェクトのプロパティ。すべてのオブジェクトがあります。
プロトタイプ:関数固有のプロパティ。
let obj = {};
console.log('__proto__' in obj); // true
console.log('prototype' in obj); // false
const fun = function () {};
console.log('__proto__' in fun); // true
console.log('prototype' in fun); // true
すべての Function オブジェクトにプロトタイプ プロパティがあるわけではありません。典型的なのはアロー関数です。
const fn = () => {};
console.log('prototype' in fn); // false
const method = ({foo () {}}).foo;
console.log('prototype' in method); // false
async function asyncFunction() {}
console.log('prototype' in asyncFunction); // false
オブジェクトの __proto__ 属性は、オブジェクトのプロトタイプを返します。
デフォルトでは、関数のプロトタイプ プロパティはオブジェクトを指します。通常の関数では、この属性は基本的に役に立ちません。コンストラクターの場合、インスタンスが生成されると、この属性は自動的にインスタンス オブジェクトのプロトタイプになります。
let obj = {};
console.log(obj.__proto__ === Object.prototype); // true
const f = function () {}
console.log(f.__proto__ === Function.prototype); // true
const F = function () {};
console.log((new F()).__proto__ === F.prototype); // true
プロトタイプ プロパティ
効果:
JavaScript 継承メカニズムの設計思想は、プロトタイプ オブジェクトのすべてのプロパティとメソッドをインスタンス オブジェクトで共有できるというものです。
コンストラクターのプロトタイプ属性は、すべてのインスタンス オブジェクトで共有されるプロパティとメソッドを定義するために使用されます。
const Cat = function (name) {
this.name = name;
}
Cat.prototype.host = '张三';
Cat.prototype.aowu = function () {
return this.name + ': 嗷呜';
}
let nuomi = new Cat('糯米');
let tangyuan = new Cat('汤圆');
console.log(nuomi.aowu === tangyuan.aowu); // true
console.log(nuomi.host); // '张三'
console.log(tangyuan.host); // '张三'
インスタンスオブジェクト自体に特定のプロパティまたはメソッドがない場合、プロトタイプオブジェクトに移動してプロパティまたはメソッドを見つけます。
インスタンスオブジェクト自体が特定のプロパティまたはメソッド を持っている場合、プロトタイプオブジェクトに移動してこのプロパティまたはメソッドを見つけることはありません。
tangyuan.host = '李四';
console.log(nuomi.host); // '张三'
console.log(tangyuan.host); // '李四'
コンストラクタ プロパティ
デフォルトでは、プロトタイプ オブジェクトにはコンストラクター属性があり、デフォルトでプロトタイプ オブジェクトのコンストラクターを指します。
const Cat = function (name) {}
console.log(Cat.prototype.constructor === Cat); // true
let nuomi = new Cat('糯米');
console.log(nuomi.constructor === Cat); // true
console.log(nuomi.hasOwnProperty('constructor')); // false
Nuomi はコンストラクター Cat のインスタンス オブジェクトですが、nuomi 自体にはコンストラクター属性がなく、実際にはプロトタイプ チェーンの Cat.prototype.constructor 属性を読み取ります。
プロトタイプを導入したら、プロトタイプ チェーンを続行します。
試作チェーン
前述のように、コンストラクターの場合、インスタンスが生成されると、prototype 属性が自動的にインスタンス オブジェクトのプロトタイプになります。
つまり、インスタンス object.__proto__ === constructor.prototype.
まず、コンストラクター F を定義し、それを使用してインスタンス オブジェクト f を生成します。f.__proto__ は、コンストラクター F のプロトタイプ プロパティを指します。たった今:
function F() {}
const f = new F();
console.log(f.__proto__ === F.prototype); // true
コンストラクター F は Function のインスタンスであるため、F.__proto__ は Function のプロトタイプ プロパティを指します。
console.log(F.__proto__ === Function.prototype); // true
デフォルトでは、関数のプロトタイプ プロパティはオブジェクトを指します。つまり、関数のプロトタイプ プロパティは Object のインスタンスです。
function.prototype の __proto__ は Object.prototype を指します。
したがって、F.prototype.__proto__ と Function.prototype.__proto__ の両方が Object.prototype を指します。
console.log(F.prototype.__proto__ === Object.prototype); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true
ただし、Function.prototype を除き、function.prototype のデータ型は「オブジェクト」です。
console.log(typeof Function.prototype); // 'function'
console.log(typeof Object.prototype); // 'object'
console.log(typeof F.prototype); // 'object'
console.log(typeof Date.prototype); // 'object'
関数 (コンストラクター、組み込み関数オブジェクト (Function、Object など) を含む) は Function のインスタンスです。Function.__proto__ は Function.prototype を指しているので、それほど難しくはありません。
console.log(Function.__proto__ === Function.prototype); // true
console.log(Object.__proto__ === Function.prototype); // true
console.log(Array.__proto__ === Function.prototype); // true
console.log(Date.__proto__ === Function.prototype); // true
console.log(RegExp.__proto__ === Function.prototype); // true
console.log(Error.__proto__ === Function.prototype); // true
console.log(Number.__proto__ === Function.prototype); // true
console.log(String.__proto__ === Function.prototype); // true
console.log(Boolean.__proto__ === Function.prototype); // true
コンストラクターではない Math には、特別な注意を払う必要があります。すべてのプロパティとメソッドは、Math オブジェクトで呼び出されます。
console.log(Math.__proto__ === Object.prototype); // true
JavaScript では、すべてのオブジェクトが独自のプロトタイプ オブジェクト (prototype) を持つことが規定されています。一方では、どのオブジェクトも他のオブジェクトのプロトタイプとして機能できますが、他方では、プロトタイプ オブジェクトもオブジェクトであるため、独自のプロトタイプも持ちます。したがって、「プロトタイプチェーン」(プロトタイプチェーン)が形成されます:オブジェクトからプロトタイプ、そしてプロトタイプのプロトタイプへ...
JavaScript では、すべてがオブジェクトです。レイヤーごとにトレースすると、すべてのオブジェクトのプロトタイプは、最終的に Object.prototype までトレースできます。つまり、すべてのオブジェクトは Object.prototype のプロパティを継承します。
Object.prototype のプロトタイプはどうですか? 無効である。null にはプロパティやメソッドがなく、独自のプロトタイプもありません。したがって、プロトタイプ チェーンの末尾は null です。
console.log(Object.prototype.__proto__ === null); // true
別の例: __proto__ は標準属性ではありません (ECMA-262 の第 5 版では、属性またはポインター [[Prototype]] を呼び出します)。デプロイする必要があるのはブラウザーだけであり、他の環境にはこの属性がない場合があります。
したがって、この属性はできるだけ使用しないようにする必要がありますが、プロトタイプ オブジェクトの読み取りと書き込みには Object.getPrototypeOf() と Object.setPrototypeOf() を使用する必要があります。
これまでのところ、プロトタイプチェーンの関連知識は基本的に整理されています。要約すると、プロトタイプ チェーンのマップを描画できます。
やっと:
instanceof 演算子: この演算子は、オブジェクトがコンストラクターのインスタンスであるかどうかを示すブール値を返します。演算子の左側がインスタンス オブジェクトで、右側がコンストラクタです。原則は、右側のコンストラクターのプロトタイプ プロパティが左側のオブジェクトのプロトタイプ チェーンにあるかどうかを確認することです。
Object.prototype.isPrototypeOf(): オブジェクトがパラメーター オブジェクトのプロトタイプであるかどうかを判断するために使用されます。
function F() {}
const f = new F();
console.log(f instanceof F); // true
console.log(f instanceof Object); // true
console.log(F.prototype.isPrototypeOf(f)); // true
console.log(Object.prototype.isPrototypeOf(f)); // true
// 一种特殊情况,判断失真
let obj = Object.create(null);
console.log(typeof obj); // 'object'
console.log(obj instanceof Object); // false
console.log(Object.prototype.isPrototypeOf(obj)); // false
終わり。