検索
ホームページウェブフロントエンドjsチュートリアルJavaScriptの継承の詳しい解説(3)_jsオブジェクト指向

注: この章の jClass の実装は、単純な JavaScript の継承 の実践を指します。

まず、第 1 章で紹介した例を確認してみましょう:

 function Person(name) {<BR>
this.name = name;<BR>
}<BR>
Person.prototype = {<BR>
getName: function() {<BR>
return this.name;<BR>
}<BR>
}<br><br>
function Employee(name, employeeID) {<BR>
this.name = name;<BR>
this.employeeID = employeeID;<BR>
}<BR>
Employee.prototype = new Person();<BR>
Employee.prototype.getEmployeeID = function() {<BR>
return this.employeeID;<BR>
};<BR>
var zhang = new Employee("ZhangSan", "1234");<BR>
console.log(zhang.getName()); // "ZhangSan" <BR>

コンストラクターのポインティングエラーを修正

前の記事のコンストラクターの説明から、以下に示すように、Employee インスタンスのコンストラクターにはポインティング エラーがあることがわかります。

 var zhang = new Employee("ZhangSan", "1234");<BR>
console.log(zhang.constructor === Employee); // false<BR>
console.log(zhang.constructor === Object); // true <BR>
簡単な修正が必要です。
 function Employee(name, employeeID) {<BR>
this.name = name;<BR>
this.employeeID = employeeID;<BR>
}<BR>
Employee.prototype = new Person();<BR>
Employee.prototype.constructor = Employee;<BR>
Employee.prototype.getEmployeeID = function() {<BR>
return this.employeeID;<BR>
};<BR>
var zhang = new Employee("ZhangSan", "1234");<BR>
console.log(zhang.constructor === Employee); // true<BR>
console.log(zhang.constructor === Object); // false<BR>

Employee クラスの作成時に person をインスタンス化するのは不適切です

しかし一方で、継承を実装するにはこのメカニズムに依存する必要があります。 解決策は、コンストラクターでデータを初期化するのではなく、データを初期化するためのプロトタイプ メソッド (init など) を提供することです。

 // 空的构造函数<BR>
function Person() {<BR>
}<BR>
Person.prototype = {<BR>
init: function(name) {<BR>
this.name = name;<BR>
},<BR>
getName: function() {<BR>
return this.name;<BR>
}<BR>
}<BR>
// 空的构造函数<BR>
function Employee() {<BR>
}<BR>
// 创建类的阶段不会初始化父类的数据,因为Person是一个空的构造函数<BR>
Employee.prototype = new Person();<BR>
Employee.prototype.constructor = Employee;<BR>
Employee.prototype.init = function(name, employeeID) {<BR>
this.name = name;<BR>
this.employeeID = employeeID;<BR>
};<BR>
Employee.prototype.getEmployeeID = function() {<BR>
return this.employeeID;<BR>
};<BR>
このメソッドでは、次のように、オブジェクトをインスタンス化した後に init 関数を手動で呼び出す必要があります。
 var zhang = new Employee();<BR>
zhang.init("ZhangSan", "1234");<BR>
console.log(zhang.getName()); // "ZhangSan"<BR>

init 関数を自動的に呼び出すにはどうすればよいですか?

クラスの構築時に init 関数を呼び出さないことと、オブジェクトのインスタンス化時に init 関数を自動的に呼び出すという 2 つの効果を達成する必要があります。空のコンストラクターを呼び出すときにステータスインジケーターが必要なようです。

しかし、これにはグローバル変数の導入が必要であり、これは悪い兆候です。
 // 创建一个全局的状态标示 - 当前是否处于类的构造阶段<BR>
var initializing = false;<BR>
function Person() {<BR>
if (!initializing) {<BR>
this.init.apply(this, arguments);<BR>
}<BR>
}<BR>
Person.prototype = {<BR>
init: function(name) {<BR>
this.name = name;<BR>
},<BR>
getName: function() {<BR>
return this.name;<BR>
}<BR>
}<BR>
function Employee() {<BR>
if (!initializing) {<BR>
this.init.apply(this, arguments);<BR>
}<BR>
}<BR>
// 标示当前进入类的创建阶段,不会调用init函数<BR>
initializing = true;<BR>
Employee.prototype = new Person();<BR>
Employee.prototype.constructor = Employee;<BR>
initializing = false;<BR>
Employee.prototype.init = function(name, employeeID) {<BR>
this.name = name;<BR>
this.employeeID = employeeID;<BR>
};<BR>
Employee.prototype.getEmployeeID = function() {<BR>
return this.employeeID;<BR>
};<br><br>
// 初始化类实例时,自动调用类的原型函数init,并向init中传递参数<BR>
var zhang = new Employee("ZhangSan", "1234");<BR>
console.log(zhang.getName()); // "ZhangSan"<BR>

グローバル変数の初期化を回避するにはどうすればよいですか?

グローバル変数の導入を避けるために内部の詳細をカプセル化しながら、クラス作成プロセスを簡素化するためにグローバル関数を導入する必要があります。

jClass 関数を使用してクラスを作成し、クラスを継承するメソッド:
 // 当前是否处于创建类的阶段<BR>
var initializing = false;<BR>
function jClass(baseClass, prop) {<BR>
// 只接受一个参数的情况 - jClass(prop)<BR>
if (typeof (baseClass) === "object") {<BR>
prop = baseClass;<BR>
baseClass = null;<BR>
}<BR>
// 本次调用所创建的类(构造函数)<BR>
function F() {<BR>
// 如果当前处于实例化类的阶段,则调用init原型函数<BR>
if (!initializing) {<BR>
this.init.apply(this, arguments);<BR>
}<BR>
}<BR>
// 如果此类需要从其它类扩展<BR>
if (baseClass) {<BR>
initializing = true;<BR>
F.prototype = new baseClass();<BR>
F.prototype.constructor = F;<BR>
initializing = false;<BR>
}<BR>
// 覆盖父类的同名函数<BR>
for (var name in prop) {<BR>
if (prop.hasOwnProperty(name)) {<BR>
F.prototype[name] = prop[name];<BR>
}<BR>
}<BR>
return F;<BR>
};<BR>
OK、クラスを作成およびインスタンス化する方法がより洗練されました。 しかし、ここには明らかな欠陥がまだあります。Employee の初期化関数 init は、親クラスの同じ名前のメソッドを呼び出すことができません。
 var Person = jClass({<BR>
init: function(name) {<BR>
this.name = name;<BR>
},<BR>
getName: function() {<BR>
return this.name;<BR>
}<BR>
});<BR>
var Employee = jClass(Person, {<BR>
init: function(name, employeeID) {<BR>
this.name = name;<BR>
this.employeeID = employeeID;<BR>
},<BR>
getEmployeeID: function() {<BR>
return this.employeeID;<BR>
}<BR>
});<br><br>
var zhang = new Employee("ZhangSan", "1234");<BR>
console.log(zhang.getName()); // "ZhangSan"<BR>

親クラスで同じ名前のメソッドを呼び出すにはどうすればよいですか?

次のように、インスタンス化されたオブジェクトの基本属性を指定することで、親クラス (コンストラクター) のプロトタイプを指定できます。

メソッドの呼び出し:
 // 当前是否处于创建类的阶段<BR>
var initializing = false;<BR>
function jClass(baseClass, prop) {<BR>
// 只接受一个参数的情况 - jClass(prop)<BR>
if (typeof (baseClass) === "object") {<BR>
prop = baseClass;<BR>
baseClass = null;<BR>
}<BR>
// 本次调用所创建的类(构造函数)<BR>
function F() {<BR>
// 如果当前处于实例化类的阶段,则调用init原型函数<BR>
if (!initializing) {<BR>
// 如果父类存在,则实例对象的base指向父类的原型<BR>
// 这就提供了在实例对象中调用父类方法的途径<BR>
if (baseClass) {<BR>
this.base = baseClass.prototype;<BR>
}<BR>
this.init.apply(this, arguments);<BR>
}<BR>
}<BR>
// 如果此类需要从其它类扩展<BR>
if (baseClass) {<BR>
initializing = true;<BR>
F.prototype = new baseClass();<BR>
F.prototype.constructor = F;<BR>
initializing = false;<BR>
}<BR>
// 覆盖父类的同名函数<BR>
for (var name in prop) {<BR>
if (prop.hasOwnProperty(name)) {<BR>
F.prototype[name] = prop[name];<BR>
}<BR>
}<BR>
return F;<BR>
};<BR>
 var Person = jClass({<BR>
init: function(name) {<BR>
this.name = name;<BR>
},<BR>
getName: function() {<BR>
return this.name;<BR>
}<BR>
});<BR>
var Employee = jClass(Person, {<BR>
init: function(name, employeeID) {<BR>
// 调用父类的原型函数init,注意使用apply函数修改init的this指向<BR>
this.base.init.apply(this, [name]);<BR>
this.employeeID = employeeID;<BR>
},<BR>
getEmployeeID: function() {<BR>
return this.employeeID;<BR>
},<BR>
getName: function() {<BR>
// 调用父类的原型函数getName<BR>
return "Employee name: " + this.base.getName.apply(this);<BR>
}<BR>
});<br><br>
var zhang = new Employee("ZhangSan", "1234");<BR>
console.log(zhang.getName()); // "Employee name: ZhangSan"<BR>

これまでのところ、第 1 章の継承の手動実装の欠点を修正してきました。 カスタム jClass 関数を通じてクラスとサブクラスを作成し、プロトタイプ メソッド init を通じてデータを初期化し、インスタンス属性ベースを通じて親クラスのプロトタイプ関数を呼び出します。

唯一の欠点は、親クラスを呼び出すコードが長すぎて理解しにくいことです。

のように呼び出すことができれば良いのではないかと思います。
 var Employee = jClass(Person, {<BR>
init: function(name, employeeID) {<BR>
// 如果能够这样调用,就再好不过了<BR>
this.base(name);<BR>
this.employeeID = employeeID;<BR>
}<BR>
});<BR>

jClass 関数の最適化

この時点で、クラスとサブクラスの作成とメソッドの呼び出しは非常にエレガントです。以下を参照してください。
 // 当前是否处于创建类的阶段<BR>
var initializing = false;<BR>
function jClass(baseClass, prop) {<BR>
// 只接受一个参数的情况 - jClass(prop)<BR>
if (typeof (baseClass) === "object") {<BR>
prop = baseClass;<BR>
baseClass = null;<BR>
}<BR>
// 本次调用所创建的类(构造函数)<BR>
function F() {<BR>
// 如果当前处于实例化类的阶段,则调用init原型函数<BR>
if (!initializing) {<BR>
// 如果父类存在,则实例对象的baseprototype指向父类的原型<BR>
// 这就提供了在实例对象中调用父类方法的途径<BR>
if (baseClass) {<BR>
this.baseprototype = baseClass.prototype;<BR>
}<BR>
this.init.apply(this, arguments);<BR>
}<BR>
}<BR>
// 如果此类需要从其它类扩展<BR>
if (baseClass) {<BR>
initializing = true;<BR>
F.prototype = new baseClass();<BR>
F.prototype.constructor = F;<BR>
initializing = false;<BR>
}<BR>
// 覆盖父类的同名函数<BR>
for (var name in prop) {<BR>
if (prop.hasOwnProperty(name)) {<BR>
// 如果此类继承自父类baseClass并且父类原型中存在同名函数name<BR>
if (baseClass &&<BR>
typeof (prop[name]) === "function" &&<BR>
typeof (F.prototype[name]) === "function") {<br><br>
// 重定义函数name - <BR>
// 首先在函数上下文设置this.base指向父类原型中的同名函数<BR>
// 然后调用函数prop[name],返回函数结果<br><br>
// 注意:这里的自执行函数创建了一个上下文,这个上下文返回另一个函数,<BR>
// 此函数中可以应用此上下文中的变量,这就是闭包(Closure)。<BR>
// 这是JavaScript框架开发中常用的技巧。<BR>
F.prototype[name] = (function(name, fn) {<BR>
return function() {<BR>
this.base = baseClass.prototype[name];<BR>
return fn.apply(this, arguments);<BR>
};<BR>
})(name, prop[name]);<br><br>
} else {<BR>
F.prototype[name] = prop[name];<BR>
}<BR>
}<BR>
}<BR>
return F;<BR>
};<BR>
 var Person = jClass({<BR>
init: function(name) {<BR>
this.name = name;<BR>
},<BR>
getName: function() {<BR>
return this.name;<BR>
}<BR>
});<BR>
var Employee = jClass(Person, {<BR>
init: function(name, employeeID) {<BR>
this.base(name);<BR>
this.employeeID = employeeID;<BR>
},<BR>
getEmployeeID: function() {<BR>
return this.employeeID;<BR>
},<BR>
getName: function() {<BR>
return "Employee name: " + this.base();<BR>
}<BR>
});<br><br>
var zhang = new Employee("ZhangSan", "1234");<BR>
console.log(zhang.getName()); // "Employee name: ZhangSan"<BR>

これまでのところ、よりエレガントな方法で JavaScript でクラスと継承を実装するのに役立つ完全な関数 jClass を作成してきました。

次の章では、インターネット上で最も人気のある JavaScript クラスの実装と継承を続けて分析します。 ただし、すべては同じままであり、これらの実装は、よりエレガントな呼び出し方法を目的として、この章で説明した概念を揺るがす「誇大宣伝」にすぎません。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
JavaScript:Web言語の汎用性の調査JavaScript:Web言語の汎用性の調査Apr 11, 2025 am 12:01 AM

JavaScriptは、現代のWeb開発のコア言語であり、その多様性と柔軟性に広く使用されています。 1)フロントエンド開発:DOM操作と最新のフレームワーク(React、Vue.JS、Angularなど)を通じて、動的なWebページとシングルページアプリケーションを構築します。 2)サーバー側の開発:node.jsは、非ブロッキングI/Oモデルを使用して、高い並行性とリアルタイムアプリケーションを処理します。 3)モバイルおよびデスクトップアプリケーション開発:クロスプラットフォーム開発は、反応および電子を通じて実現され、開発効率を向上させます。

JavaScriptの進化:現在の傾向と将来の見通しJavaScriptの進化:現在の傾向と将来の見通しApr 10, 2025 am 09:33 AM

JavaScriptの最新トレンドには、TypeScriptの台頭、最新のフレームワークとライブラリの人気、WebAssemblyの適用が含まれます。将来の見通しは、より強力なタイプシステム、サーバー側のJavaScriptの開発、人工知能と機械学習の拡大、およびIoTおよびEDGEコンピューティングの可能性をカバーしています。

javascriptの分解:それが何をするのか、なぜそれが重要なのかjavascriptの分解:それが何をするのか、なぜそれが重要なのかApr 09, 2025 am 12:07 AM

JavaScriptは現代のWeb開発の基礎であり、その主な機能には、イベント駆動型のプログラミング、動的コンテンツ生成、非同期プログラミングが含まれます。 1)イベント駆動型プログラミングにより、Webページはユーザー操作に応じて動的に変更できます。 2)動的コンテンツ生成により、条件に応じてページコンテンツを調整できます。 3)非同期プログラミングにより、ユーザーインターフェイスがブロックされないようにします。 JavaScriptは、Webインタラクション、シングルページアプリケーション、サーバー側の開発で広く使用されており、ユーザーエクスペリエンスとクロスプラットフォーム開発の柔軟性を大幅に改善しています。

pythonまたはjavascriptの方がいいですか?pythonまたはjavascriptの方がいいですか?Apr 06, 2025 am 12:14 AM

Pythonはデータサイエンスや機械学習により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、簡潔な構文とリッチライブラリエコシステムで知られており、データ分析とWeb開発に適しています。 2。JavaScriptは、フロントエンド開発の中核です。 node.jsはサーバー側のプログラミングをサポートしており、フルスタック開発に適しています。

JavaScriptをインストールするにはどうすればよいですか?JavaScriptをインストールするにはどうすればよいですか?Apr 05, 2025 am 12:16 AM

JavaScriptは、最新のブラウザにすでに組み込まれているため、インストールを必要としません。開始するには、テキストエディターとブラウザのみが必要です。 1)ブラウザ環境では、タグを介してHTMLファイルを埋め込んで実行します。 2)node.js環境では、node.jsをダウンロードしてインストールした後、コマンドラインを介してJavaScriptファイルを実行します。

クォーツでタスクが開始される前に通知を送信する方法は?クォーツでタスクが開始される前に通知を送信する方法は?Apr 04, 2025 pm 09:24 PM

Quartzタイマーを使用してタスクをスケジュールする場合、Quartzでタスク通知を事前に送信する方法、タスクの実行時間はCron式によって設定されます。今...

JavaScriptでは、コンストラクターのプロトタイプチェーンで関数のパラメーターを取得する方法は?JavaScriptでは、コンストラクターのプロトタイプチェーンで関数のパラメーターを取得する方法は?Apr 04, 2025 pm 09:21 PM

JavaScriptプログラミング、プロトタイプチェーンの関数パラメーターの理解と操作のJavaScriptのプロトタイプチェーンの関数のパラメーターを取得する方法は、一般的で重要なタスクです...

WeChat MiniプログラムWebViewでVUE.JSダイナミックスタイルの変位が失敗した理由は何ですか?WeChat MiniプログラムWebViewでVUE.JSダイナミックスタイルの変位が失敗した理由は何ですか?Apr 04, 2025 pm 09:18 PM

WeChatアプレットWeb-ViewでVue.jsを使用する動的スタイルの変位障害がvue.jsを使用している理由の分析...

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

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

ホットツール

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

SublimeText3 Mac版

SublimeText3 Mac版

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

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール