JavaScript のプロトタイプと継承についての詳細
この記事では主に、JavaScript でプロトタイプがどのように機能するか、すべてのオブジェクトで共有される [プロトタイプ] の非表示プロパティを介してオブジェクトのプロパティとメソッドをリンクする方法、およびカスタム コンストラクターを作成する方法と、プロパティとメソッドの値を渡すためにプロトタイプの継承がどのように機能するかについて説明します。 。
#はじめに
JavaScript ビデオ チュートリアル ]
この記事では、オブジェクト プロトタイプとは何か、コンストラクターを使用してプロトタイプを拡張する方法について学びます。新しいオブジェクト。継承とプロトタイプ チェーンについても学習します。JavaScript プロトタイプ
JavaScript のすべてのオブジェクトには、[[プロトタイプ]] と呼ばれる内部プロパティがあります。新しい空のオブジェクトを作成することで、これを実証できます。let x = {};
let x = new object()
[[Prototype]] を囲む角かっこは、次のことを示します。これは内部プロパティであり、コードから直接アクセスできないこと。
この新しく作成されたオブジェクトの [[プロトタイプ]] を見つけるには、getPrototypeOf() メソッドを使用します。Object.getPrototypeOf(x);
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}
x.__proto__;
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}
#プロトタイプの継承
#オブジェクトのプロパティまたはメソッドにアクセスしようとすると、JavaScript は最初にオブジェクトを検索します。それ自体が見つからない場合は、オブジェクトの [[Prototype]] を検索します。オブジェクトとその [[Prototype]] をクエリした後に一致が見つからない場合、JavaScript はリンクされたオブジェクトのプロトタイプをチェックし、プロトタイプ チェーンの最後に到達するまで検索を続けます。
#プロトタイプ チェーンの最後は Object.prototype です。すべてのオブジェクトは、オブジェクトのプロパティとメソッドを継承します。チェーンの終わりを超えて検索すると、結果は null になります。
x.toString();
[object Object]
このプロトタイプ チェーンの長さは 1 チェーンのみです。 x - > オブジェクト。 2 つの [[Prototype]] プロパティを連結しようとすると null になるため、これがわかります。
x.__proto__.__proto__;
null
別のタイプのオブジェクトを見てみましょう。 JavaScript で配列を操作した経験がある場合は、pop() や Push() など、配列に多くの組み込みメソッドがあることをご存知でしょう。新しい配列の作成時にこれらのメソッドにアクセスできるのは、作成されたすべての配列が array.prototype のプロパティとメソッドにアクセスできるためです。
let y = [];
y.__proto__;
[constructor: ƒ, concat: ƒ, pop: ƒ, push: ƒ, …]
y.__proto__.__proto__;
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}
y.__proto__ === Array.prototype; // true y.__proto__.__proto__ === Object.prototype; // true
Array.prototype.isPrototypeOf(y); // true Object.prototype.isPrototypeOf(Array); // true
我们可以使用instanceof操作符来测试构造函数的prototype属性是否出现在对象原型链中的任何位置。
y instanceof Array; // true
总而言之,所有JavaScript对象都具有隐藏的内部[[Prototype]]属性(可能__proto__在某些浏览器中公开)。对象可以扩展,并将继承[[Prototype]]其构造函数的属性和方法。
这些原型可以被链接,并且每个额外的对象将继承整个链中的所有内容。链以Object.prototype结束。
构造器函数
构造函数是用来构造新对象的函数。new操作符用于基于构造函数创建新实例。我们已经看到了一些内置的JavaScript构造函数,比如new Array()和new Date(),但是我们也可以创建自己的自定义模板来构建新对象。
例如,我们正在创建一个非常简单的基于文本的角色扮演游戏。用户可以选择一个角色,然后选择他们将拥有的角色类别,例如战士、治疗者、小偷等等。
由于每个字符将共享许多特征,例如具有名称、级别和生命值,因此创建构造函数作为模板是有意义的。然而,由于每个角色类可能有非常不同的能力,我们希望确保每个角色只能访问自己的能力。让我们看看如何使用原型继承和构造函数来实现这一点。
首先,构造函数只是一个普通函数。当使用new关键字的实例调用它时,它将成为一个构造函数。在JavaScript中,我们按照惯例将构造函数的第一个字母大写。
// Initialize a constructor function for a new Hero function Hero(name, level) { this.name = name; this.level = level; }
我们创建了一个名为Hero的构造函数,它有两个参数:name和level。因为每个字符都有一个名称和一个级别,所以每个新字符都有这些属性是有意义的。this关键字将引用创建的新实例,因此将this.name设置为name参数将确保新对象具有name属性集。
现在我们可以用new创建一个新的实例。
let hero1 = new Hero('Bjorn', 1);
如果我们在控制台输出hero1,我们将看到已经创建了一个新对象,其中新属性按预期设置。
输出
Hero {name: "Bjorn", level: 1}
现在,如果我们得到hero1的[[Prototype]],我们将能够看到构造函数Hero()。(记住,它的输入与hero1相同。,但这是正确的方法。)
Object.getPrototypeOf(hero1);
输出
constructor: ƒ Hero(name, level)
您可能注意到,我们只在构造函数中定义了属性,而没有定义方法。在JavaScript中,为了提高效率和代码可读性,通常在原型上定义方法。
我们可以使用prototype向Hero添加一个方法。我们将创建一个greet()方法。
// Add greet method to the Hero prototype Hero.prototype.greet = function () { return `${this.name} says hello.`; }
因为greet()在Hero的原型中,而hero1是Hero的一个实例,所以这个方法对hero1是可用的。
hero1.greet();
输出
"Bjorn says hello."
如果检查Hero的[[Prototype]],您将看到greet()现在是一个可用选项。
这很好,但是现在我们想要为英雄创建角色类。将每个类的所有功能都放到Hero构造函数中是没有意义的,因为不同的类具有不同的功能。我们希望创建新的构造函数,但也希望它们连接到原始的Hero。
我们可以使用call()方法将属性从一个构造函数复制到另一个构造函数。让我们创建一个战士和一个治疗构造器。
// Initialize Warrior constructor function Warrior(name, level, weapon) { // Chain constructor with call Hero.call(this, name, level); // Add a new property this.weapon = weapon; }// Initialize Healer constructor function Healer(name, level, spell) { Hero.call(this, name, level); this.spell = spell; }
两个新的构造函数现在都具有Hero和unqiue的属性。我们将把attack()方法添加到Warrior中,而heal()方法添加到Healer中。
Warrior.prototype.attack = function () { return `${this.name} attacks with the ${this.weapon}.`; } Healer.prototype.heal = function () { return `${this.name} casts ${this.spell}.`; }
此时,我们将使用两个可用的新字符类创建字符。
const hero1 = new Warrior('Bjorn', 1, 'axe'); const hero2 = new Healer('Kanin', 1, 'cure');
hero1现在被认为是拥有新属性的战士。
输出
Warrior {name: "Bjorn", level: 1, weapon: "axe"}
我们可以使用我们在战士原型上设置的新方法。
hero1.attack();
Console "Bjorn attacks with the axe."
但是如果我们尝试使用原型链下面的方法会发生什么呢?
hero1.greet();
输出
Uncaught TypeError: hero1.greet is not a function
使用call()链接构造函数时,原型属性和方法不会自动链接。我们将使用Object.create()来链接原型,确保在创建并添加到原型的任何其他方法之前将其放置。
Warrior.prototype = Object.create(Hero.prototype); Healer.prototype = Object.create(Hero.prototype); // All other prototype methods added below…
现在我们可以在一个战士或治疗者的实例上成功地使用Hero的原型方法。
hero1.greet();
输出
"Bjorn says hello."
这里是我们的角色创建页面的完整代码。
// Initialize constructor functions function Hero(name, level) { this.name = name; this.level = level; } function Warrior(name, level, weapon) { Hero.call(this, name, level); this.weapon = weapon; } function Healer(name, level, spell) { Hero.call(this, name, level); this.spell = spell; } // Link prototypes and add prototype methods Warrior.prototype = Object.create(Hero.prototype); Healer.prototype = Object.create(Hero.prototype); Hero.prototype.greet = function () { return `${this.name} says hello.`; } Warrior.prototype.attack = function () { return `${this.name} attacks with the ${this.weapon}.`; } Healer.prototype.heal = function () { return `${this.name} casts ${this.spell}.`; } // Initialize individual character instances const hero1 = new Warrior('Bjorn', 1, 'axe'); const hero2 = new Healer('Kanin', 1, 'cure');
使用这段代码,我们已经用基本属性创建了Hero类,从原始构造函数创建了两个名为Warrior和Healer的字符类,向原型添加了方法,并创建了单独的字符实例。
この記事は js チュートリアル 列からのものです。ぜひ学習してください。
以上がJavaScript のプロトタイプと継承についての詳細の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









関数の継承では、「基底クラス ポインター」と「派生クラス ポインター」を使用して継承メカニズムを理解します。基底クラス ポインターが派生クラス オブジェクトを指す場合、上方変換が実行され、基底クラスのメンバーのみにアクセスされます。派生クラス ポインターが基本クラス オブジェクトを指す場合、下向きキャストが実行される (安全ではない) ため、注意して使用する必要があります。

継承とポリモーフィズムはクラスの結合に影響します。派生クラスは基本クラスに依存するため、継承により結合が増加します。ポリモーフィズムにより、オブジェクトは仮想関数と基本クラス ポインターを通じて一貫した方法でメッセージに応答できるため、結合が軽減されます。ベスト プラクティスには、継承を控えめに使用すること、パブリック インターフェイスを定義すること、基本クラスへのデータ メンバーの追加を回避すること、依存関係の注入を通じてクラスを分離することが含まれます。ポリモーフィズムと依存性注入を使用して銀行口座アプリケーションの結合を軽減する方法を示す実践的な例。

継承エラーのデバッグのヒント: 正しい継承関係を確認します。デバッガーを使用してコードをステップ実行し、変数値を調べます。仮想修飾子を正しく使用してください。隠れた相続によって引き起こされる相続ダイアモンド問題を調べてください。抽象クラスに実装されていない純粋仮想関数がないか確認します。

C++の関数継承を詳しく解説:「is-a」と「has-a」の関係をマスターしよう 関数継承とは?関数の継承は、派生クラスで定義されたメソッドを基本クラスで定義されたメソッドに関連付ける C++ の手法です。これにより、派生クラスが基本クラスのメソッドにアクセスしてオーバーライドできるようになり、基本クラスの機能が拡張されます。 「is-a」および「has-a」関係 関数継承では、「is-a」関係は、派生クラスが基本クラスのサブタイプであること、つまり、派生クラスが基本クラスの特性と動作を「継承」することを意味します。基本クラス。 「has-a」関係は、派生クラスに基本クラス オブジェクトへの参照またはポインターが含まれていること、つまり、派生クラスが基本クラス オブジェクトを「所有」していることを意味します。構文関数継承を実装する方法の構文は次のとおりです: classDerivedClass:pu

原神 バージョン 4.4 の新しいマップの紹介. 皆さん、原神 4.4 バージョンでは、立月のシー ランタン フェスティバルも始まりました. 同時に、バージョン 4.4 では神羽渓谷と呼ばれる新しいマップ エリアが開始されます。提供された情報によると、沈雨谷は実際には喬営村の一部ですが、プレイヤーはそれを沈雨谷と呼ぶことに慣れています。それでは、新しい地図をご紹介します。原神バージョン 4.4 の新マップのご紹介です。バージョン 4.4 では、立月北部に「陳兪渓谷・上谷」、「陳兪渓谷・南嶺」、「来新山」がオープンします。谷・上谷」。 ※魔神クエスト・第3幕「ドラゴンと自由の歌」プロローグをクリアすると、テレポートアンカーポイントが自動で解放されます。 2. 喬営荘 暖かい春風が再び陳嶼の山野を撫でるとき、香りのよい

オブジェクト指向プログラミングとは何ですか?オブジェクト指向プログラミング (OOP) は、現実世界のエンティティをクラスに抽象化し、オブジェクトを使用してこれらのエンティティを表すプログラミング パラダイムです。クラスはオブジェクトのプロパティと動作を定義し、オブジェクトはクラスをインスタンス化します。 OOP の主な利点は、コードの理解、保守、再利用が容易になることです。 OOP の基本概念 OOP の主な概念には、クラス、オブジェクト、プロパティ、メソッドが含まれます。クラスはオブジェクトの設計図であり、オブジェクトのプロパティと動作を定義します。オブジェクトはクラスのインスタンスであり、クラスのすべてのプロパティと動作を備えています。プロパティは、データを保存できるオブジェクトの特性です。メソッドは、オブジェクトのデータを操作できるオブジェクトの関数です。 OOP の利点 OOP の主な利点は次のとおりです。 再利用性: OOP はコードをより高度なものにすることができます。

C++ 関数の継承は、次の状況では使用しないでください。 派生クラスが異なる実装を必要とする場合、異なる実装を持つ新しい関数を作成する必要があります。派生クラスが関数を必要としない場合は、空のクラスとして宣言するか、プライベートの未実装の基本クラス メンバー関数を使用して関数の継承を無効にする必要があります。関数が継承を必要としない場合は、コードの再利用を実現するために他のメカニズム (テンプレートなど) を使用する必要があります。

インターフェイス: 実装のないコントラクト インターフェイスは、Java でメソッド シグネチャのセットを定義しますが、具体的な実装は提供しません。これは、インターフェイスを実装するクラスに、その指定されたメソッドを強制的に実装するコントラクトとして機能します。インターフェイス内のメソッドは抽象メソッドであり、メソッド本体はありません。コード例: publicinterfaceAnimal{voideat();voidsleep();} 抽象クラス: 部分的に実装されたブループリント 抽象クラスは、そのサブクラスによって継承できる部分的な実装を提供する親クラスです。インターフェイスとは異なり、抽象クラスには具体的な実装と抽象メソッドを含めることができます。抽象メソッドは、abstract キーワードを使用して宣言され、サブクラスによってオーバーライドされる必要があります。コード例: publicabstractcla
