そのため、JavaScriptコードにバグがあり、適度に夢中になっています。私はJavaScriptで古典的な継承を模倣しようとしています(ここで読んだ投稿の半分は、JavaScriptをそのようなフレームワークにねじらないように言っていますが、私のアプリケーションには、サーバー側のphpコードの継承構造)。そして、ほとんどの場合、すべてが機能しているように見えます。クラスを拡張するために使用している関数は次のとおりです。
Function.prototype.inheritsFrom = function(parentClass) {
//:: Ordinary Classes
if (parentClass.constructor == Function) {
this.prototype = new parentClass();
this.prototype.constructor = this;
this.prototype.parent = parentClass.prototype;
//:: Abstract Classes
} else {
this.prototype = parentClass;
this.prototype.constructor = this;
this.prototype.parent = parentClass;
}
return this;
}
私自身の作品ではなく、オンラインで見つけましたが、うまく機能しています。追加する必要があるのは、プロトタイプチェーンで親メソッドを検索するための「スーパー」関数だけでした。前述のコードの親構造は、すべての場合に機能するとは限りません。
いずれにせよ、コードのバグを修正していると、ベース「クラス」のメソッドの1つが、すべてのサブクラスから作成されたすべてのインスタンスの同じ変数にアクセス/変更していることがわかりました。つまり、1つのインスタンスが、そのオブジェクトコンテキストに対してローカルである必要があるこの変数を変更するときはいつでも、実際には、すべてのインスタンス間で共有されるいくつかの変数を変更します。基本クラスは次のとおりです。
function DataManipulatorControl() {
//|| Private Members ||//
var that = this;
//|| Properties ||//
//|| Root ID
this.rootID = function(value) {
if (value !== undefined) {
if (_root_id !== null) {
alert('@ ' + _root_id);
$('#' + _root_id).prop('js_object', null);
}
_root_id = value;
$('#' + _root_id).prop('js_object', this);
}
return _root_id;
}
var _root_id = null;
// other properties/methods
}
//|| Class: DataManipulatorContainerControl
function DataManipulatorContainerControl() {
//|| Private Members ||//
var that = this;
// subclass properties/methods
}
DataManipulatorContainerControl.inheritsFrom(DataManipulatorControl);
前述したように、これらのプロトタイプの新しいインスタンスを作成すると、1つのインスタンスのrootIDを変更すると、すべてのインスタンスのrootIDが変更されることがわかりました。私の最初の考えは、どこかで「var」を忘れてしまったこと、そして私の関数がグローバルコンテキストにアクセスしていることでした。しかし、そうではないようです。次の考えは、プロトタイプのローカル変数を使用しているということです。プロトタイプのコンストラクター呼び出しのローカル変数は、スコープ内に既にあるメソッドからアクセスしない限り、プロトタイプのコンストラクター呼び出しの外部からアクセスできないようにする必要があるため、これも私にはあまり意味がありません。もちろん、rootID()関数にはスコープがありますが、プロトタイプではなく、呼び出し元のオブジェクトのオブジェクトコンテキストを使用して実行されるという印象を受けました。
だから、私は非常に混乱しています。この問題に当てることができるどんな光も、多くの感謝を呼び起こすでしょう。
編集:PRBが提供する記事では、この問題をきれいに解決するソリューションについて説明しています-ほとんどの場合。この記事では、すべてを正しく初期化するには、子クラスのコンストラクター内から親クラスのコンストラクターも呼び出す必要があると述べています。その結果、すべてのメソッドが新しく作成され、親クラスのローカル変数の独自のバージョンがクロージャに含まれます。
このアプローチには1つの欠点があるようです(すべてのインスタンスで関数を複製することによる効率の問題は別として)。超機能を試みてプロトタイプチェーンから「オーバーライドされた」関数を呼び出そうとすると、この問題が再発します。プロトタイプは、以前と同様に、単一のオブジェクトのインスタンスであり、関数のバージョンを呼び出そうとすると、インスタンスのローカル変数にアクセスしようとします。
すべてのデータを公開することを除けば、それでも私が見た中で最高の解決策です:-)。