Js の継承とプロトタイプチェーンを理解するのに役立つ記事

Js の継承とプロトタイプチェーンを理解するのに役立つ記事

継承とプロトタイプチェーン

継承に関しては、JavaScript にはオブジェクトという 1 つの構成要素しかありません。各インスタンス オブジェクトには、そのコンストラクターのプロトタイプ オブジェクトを指すプライベート プロパティ (proto と呼ばれる) があります。プロトタイプ オブジェクトにも独自のプロトタイプ オブジェクト (proto) があり、オブジェクトのプロトタイプ オブジェクトが null になるまでレイヤーごとに続きます。定義上、 null にはプロトタイプがなく、このプロトタイプ チェーンの最後のリンクとして機能します。

JavaScript のほぼすべてのオブジェクトは、プロトタイプ チェーンの最上位にある Object のインスタンスです。

継承されたプロパティ

JavaScript オブジェクトは、プロパティの動的な「バッグ」です (オブジェクト自身のプロパティを参照します)。 JavaScript オブジェクトにはプロトタイプ オブジェクトへのリンクがあります。オブジェクトのプロパティにアクセスしようとすると、一致する名前のプロパティが見つかるか、プロトタイプ チェーンの最後まで到達するまで、オブジェクトだけでなく、オブジェクトのプロトタイプ、オブジェクトのプロトタイプのプロトタイプなども検索されます。

コードサンプル

関数fn() {
  1 を返します。
  2 を 0 にします。
}

定数o = 新しいfn();

fn.prototype.b = 3;
プロトタイプは 4 です。
コンソールにログ出力します。
コンソールにログ出力します。
コンソールにログ出力します。
コンソールにログ出力します。
// 1
// 2
// 4
// 未定義
  • aとbはoのプロパティであり、直接値を返すことができます
  • fn.prototype.b = 3 に設定しているのに、返される値がまだ 2 なのはなぜでしょうか?なぜなら、私たちが自分自身の中でこの属性を探すとき、それを直接返し、上で探すことはないからです。
  • c は o の属性ではないため、o.prototype で検索され、c が見つかった場合はその値が直接返されます。
  • d は o の属性ではないため、o.prototype で検索します。見つからない場合は、o.protype.prototype で検索します。null の場合は、検索を停止し、undefined を返します。

oコンストラクタの出力を見てください

{
    1: 1
    2 倍
    __proto__:
        3 です
        4 文字
        コンストラクタ: ƒ fn()
        __proto__:
            コンストラクタ: ƒ Object()
            hasOwnProperty: ƒ hasOwnProperty()
            isPrototypeOf: ƒ isPrototypeOf()
            propertyIsEnumerable: ƒ propertyIsEnumerable()
            toLocaleString: ƒ toLocaleString()
            toString: ƒtoString()
            値: ƒ valueOf()
            __defineGetter__: ƒ __defineGetter__()
            __defineSetter__: ƒ __defineSetter__()
            __lookupGetter__: ƒ __lookupGetter__()
            __lookupSetter__: ƒ __lookupSetter__()
            __proto__ を取得する: ƒ __proto__()
            __proto__ を設定する: ƒ __proto__()
}

継承されたメソッド

JavaScript には、他のクラスベースの言語で定義されている「メソッド」はありません。 JavaScript では、任意の関数をオブジェクトのプロパティとしてオブジェクトに追加できます。関数の継承は、前述の「プロパティ シャドウイング」(他の言語でのメソッドのオーバーライドに相当) を含む他のプロパティの継承と変わりません。

継承された関数が呼び出されると、継承された関数が配置されているプロトタイプ オブジェクトではなく、現在の継承されたオブジェクトが参照されます。

var o = {
  a: 2、
  m: 関数 () {
    this.a + 1 を返します。
  },
};

コンソール.log(om()); // 3
// om を呼び出す場合、'this' は o を参照します。

var p = Object.create(o);
// p は o から継承したオブジェクトです pa = 4; // p 独自の属性 'a' を作成します
コンソールログ(pm()); // 5
// pmを呼び出すとき、'this'はpを指します
// そして、p は o の m 関数を継承しているので、 // したがって、「this.a」、つまり pa は p 自身の属性「a」です

JavaScript でのプロトタイプの使用

JavaScript では、関数にプロパティを持たせることができます。すべての関数にはプロトタイプと呼ばれる特別なプロパティがあります。デフォルトでは、Objectのプロトタイプオブジェクトです。

関数doSomething() {}
コンソールにログ出力します。
// 関数の宣言方法とは関係ありません。
// JavaScript の関数には常にデフォルトのプロトタイプ プロパティがあります。
var doSomething = function() {};
コンソールにログ出力します。

コンソールに表示される JavaScript コード ブロックには、doSomething 関数のデフォルトのプロパティ プロトタイプが表示されます。このコードを実行すると、コンソールに次のような結果が表示されます。

{
    コンストラクタ: ƒ doSomething(),
    __proto__: {
        コンストラクタ: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        値: ƒ valueOf()
    }
}

次のように、doSomething 関数のプロトタイプ オブジェクトに新しいプロパティを追加できます。

関数doSomething() {}
doSomething.prototype.foo = "bar";
コンソールにログ出力します。

実行後の結果は次のように確認できます。

{
    foo: "バー",
    コンストラクタ: ƒ doSomething(),
    __proto__: {
        コンストラクタ: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        値: ƒ valueOf()
    }
}

これで、 new 演算子を使用して、このプロトタイプ オブジェクトに基づいて doSomething のインスタンスを作成できます。

コード:

関数doSomething() {}
doSomething.prototype.foo = "bar"; // プロトタイプにプロパティを追加する
var doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value"; // オブジェクトにプロパティを追加します
console.log(インスタンス化を実行します);

実行結果は次のステートメントのようになります。

{
    プロパティ: "何らかの値"、
    __proto__: {
        foo: "バー",
        コンストラクタ: ƒ doSomething(),
        __proto__: {
            コンストラクタ: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            値: ƒ valueOf()
        }
    }
}

propはdoSomeInstancing自体のプロパティであり、doSomeInstancingのprotoはdoSomething.prototypeであることがわかります。

内部のプロパティを印刷します

console.log("doSomeInstancing.prop: " + doSomeInstancing.prop);
console.log("doSomeInstancing.foo: " + doSomeInstancing.foo);
console.log("doSomething.prop: " + doSomething.prop);
console.log("doSomething.foo: " + doSomething.foo);
console.log("doSomething.prototype.prop: " + doSomething.prototype.prop);
console.log("doSomething.prototype.foo: " + doSomething.prototype.foo);

結果は次のとおりです。

// doSomeInstancing の独自のプロパティ、値を直接返す doSomeInstancing.prop: some value
// これは doSomeInstancing 自体のプロパティではありません。プロトタイプ オブジェクトを確認し、値 doSomeInstancing.foo を直接返すこのプロパティがあることを確認します: bar
// これは関数自体のプロパティでも、プロトタイプオブジェクトのプロパティでもありません。レイヤーごとに検索して最終的にプロトタイプが null であることがわかった場合、そのようなプロパティは存在しないため、undefined を返します。
doSomething.prop: 未定義
doSomething.foo: 未定義
doSomething.prototype.prop: 未定義
// doSomething のプロトタイプ オブジェクトを見つけ、foo プロパティを持っているので、値 doSomething.prototype.foo: bar を直接返します。

パフォーマンス

プロトタイプ チェーン上のプロパティの検索は時間がかかり、パフォーマンスに副作用をもたらします。これは、パフォーマンスが重要な状況では重要です。さらに、存在しないプロパティにアクセスしようとすると、プロトタイプ チェーン全体が走査されます。

オブジェクトのプロパティを走査すると、プロトタイプ チェーン上の列挙可能な各プロパティが列挙されます。オブジェクトに、プロトタイプ チェーン上のプロパティではなく、オブジェクト自体が定義するプロパティがあるかどうかを確認するには、すべてのオブジェクトが Object.prototype から継承する hasOwnProperty メソッドを使用する必要があります。これを説明する具体的な例を以下に示します。

console.log(doSomeInstancing.hasOwnProperty("prop"));
// 真実

console.log(doSomeInstancing.hasOwnProperty("bar"));
// 間違い

console.log(doSomeInstancing.hasOwnProperty("foo"));
// 間違い

console.log(doSomeInstancing.__proto__.hasOwnProperty("foo"));
// 真実

hasOwnProperty は、プロパティを処理し、プロトタイプ チェーンを走査しない JavaScript の唯一のメソッドです。

同様のメソッドとしては、Object.keys() などがあります。

注意: プロパティが未定義かどうかをチェックすることは、そのプロパティが存在するかどうかを確認する方法ではありません。プロパティはすでに存在している可能性がありますが、その値は undefined に設定されているだけです。

付録: プロトタイプチェーンは継承を実現する主な方法です

まず継承についてお話しましょう。多くのオブジェクト指向言語は、インターフェース継承と実装継承という 2 つの継承方法をサポートしています。

|- インターフェース継承: メソッドシグネチャのみを継承する

|- 実装継承: 実際のメソッドを継承する

関数にはシグネチャがないため、ECMAScript ではインターフェース継承を実装できません。実装継承のみがサポートされており、実装継承は主にプロトタイプ チェーンを通じて実現されます。

プロトタイプチェーンの基本的な考え方:

プロトタイプを使用すると、ある参照型が別の参照型のプロパティとメソッドを継承できるようになります。

各コンストラクターにはプロトタイプ オブジェクトがあり、その中にはコンストラクターへのポインター (constructor) が含まれます。また、インスタンス オブジェクトにはプロトタイプ オブジェクトへの内部ポインター (__proto__) が含まれます。プロトタイプ オブジェクトを別の型のインスタンスと同じにすると、プロトタイプ オブジェクトには別のプロトタイプ (__proto__) へのポインターが含まれ、他のプロトタイプにも別のコンストラクター関数 (constructor) へのポインターが含まれます。別のプロトタイプが別のタイプのインスタンスである場合、インスタンスとプロトタイプのチェーンが形成されます。

プロトタイプチェーンの基本的な考え方(図):

要約する

Js 継承とプロトタイプ チェーンに関するこの記事はこれで終わりです。Js 継承とプロトタイプ チェーンに関するより関連性の高いコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Javascript プロトタイプとプロトタイプチェーンをご存知ですか?
  • JavaScript のコンストラクター、プロトタイプ、プロトタイプ チェーン、new についてどれくらい知っていますか?
  • JavaScriptプロトタイプチェーン図のまとめと実践
  • JavaScript プロトタイプとプロトタイプチェーンの深い理解
  • JavaScript プロトタイプチェーンを理解するための 2 つの図
  • JavaScriptプロトタイプとプロトタイプチェーンの詳細な説明

<<:  IE6かどうかを判定する最短JS(IEの書き方)

>>:  MySQL トランザクション分離レベルとロックメカニズムの問題に関する深い理解

推薦する

MySQL バッチ追加および保存メソッドの例

ストレステストにログインする際には、多くの異なるユーザーが必要となり、データベースに新しいデータを追...

MySQLデータベースホスト127.0.0.1とlocalhostの違い

私の友人の多くは、127.0.0.1 と localhost の違いがわからず、問題に遭遇するかもし...

Linux LVM 論理ボリューム構成プロセス (作成、増加、削減、削除、アンインストール) の詳細な説明

Linux LVM論理ボリューム構成プロセスの詳細な説明多くの Linux ユーザーは、オペレーティ...

jsは古典的なマインスイーパゲームを実装します

この記事の例では、古典的なマインスイーパゲームを実装するためのjsの具体的なコードを参考までに共有し...

Centos7 環境でバイナリ インストール パッケージから mysql5.6 をインストールする方法の詳細な説明

この記事では、centos7 環境でバイナリ インストール パッケージを使用して mysql5.6 ...

Reactにおけるコンテキスト適用シナリオの分析

コンテキストの定義と目的コンテキストは、コンポーネント ツリーにプロパティを明示的に渡すことなく、コ...

Linuxテキスト処理ツールの詳細な説明

1. /etc/passwdファイル内のデフォルトシェルが/sbin/nologinではないユーザー...

Linux CRM デプロイメント コードの詳細な説明

Linuxの基本設定 Linux環境でpython3をコンパイルしてインストールする 1. Linu...

CSSを使用してTDのINPUTの幅を設定する

最近、C# を使用して Web プログラムを作成していたときに、次のような問題が発生しました。 Te...

docker-composeの詳細なインストールと使用方法

Docker Compose は、複雑なアプリケーションを定義および実行するための Docker ツ...

Unicode の数学記号の概要

数学、物理学、および一部の科学技術分野で使用される特殊記号は多数あります。Unicode コードには...

シンプルな CSS テキストアニメーション効果

成果を達成する 実装コードhtml <div id=コンテナ> いらっしゃいませ <...

Nest.js のハッシュと暗号化の例の詳細な説明

0x0 はじめにまず、ハッシュアルゴリズムとは何でしょうか?メッセージやセッション項目など、一部のデ...

MySQLデータベースのSYNフラッディング問題を解決する

Syn 攻撃は、最も一般的で最も簡単に悪用される攻撃方法です。TCP プロトコルの欠陥を利用して、偽...