0

ユーザーが最初の選択を行うメイン メニューから始まる、かなり複雑な Web アプリを構築しています。JavaScript で継承を使用して真の OOP アプローチを試したのはこれが初めてで、「this」キーワードが期待するものを参照していないという最初の問題に遭遇しました。これは、OOP/継承アプローチのより広範な問題の結果であると推測しているため、この個々の問題を解決する方法を教えてくれるだけでなく、一般的なアプローチに関するより深いフィードバックとアドバイスを提供してくれる回答をいただければ幸いです。

HTML は関係ないと思うので、JS コードのみを投稿しますが、必要に応じて投稿することもできます。

次のコードは、メイン クラスを定義しますSelectSelect次に、 calledのサブクラスを作成しますSelectNum(コードの最後を見てください)。では、 のメソッドSelectNumをオーバーライドしようとしていますが、完全ではありません。最初にスーパーの (Select の) メソッドを呼び出してから、追加のコードを実行したいと考えています。しかし、このサブクラスのメソッドが実行されると、すぐに次のエラーが発生します。mouseoverSelectmouseover

「キャッチされていない TypeError: 未定義のメソッド 'stop' を呼び出せません」

基本的にthis.shine未定義です。

まず、O'Reilly の JavaScript: The Definitive Guide の次のコードを使用しています。

function inherit(p) {
   if (Object.create){ // If Object.create() is defined...
      return Object.create(p); // then just use it.
    }

   function f() {}; // Define a dummy constructor function.
   f.prototype = p; // Set its prototype property to p.
   return new f(); // Use f() to create an "heir" of p.
}

そして私のコード:

Select = function(el){
    return this.init(el);
}

Select.prototype = {
    init: function(el){
        var that = this;
        this.el = el;
        this.shine = el.children('.selectShine');

        el.hover(function(){
            that.mouseover();
        },function(){
            that.mouseout();
        });

        return this;
    },
    mouseover: function(){
        this.shine.stop().animate({opacity:.35},200);
    },
    mouseout: function(){
        var that = this;
        this.shine.stop().animate({opacity:.25},200);
    }
}

//Sub-classes
SelectNum = function(el){
    this.init(el);
    this.sup = inherit(Select.prototype); //allows access to super's original methods even when overwritten in this subclass
    return this;
}

SelectNum.prototype = inherit(Select.prototype);
SelectNum.prototype.mouseover = function(){
    this.sup.mouseover(); //call super's method... but this breaks down
    //do some other stuff
}

EDIT Raynosからの応答が機能しました。this.sup.mouseover()エラーをスローしなくなり、正しいコードが実行されました。ただし、実際には というSelectNumサブクラスを作成する必要がありますSelectLevelSelectNumスーパークラスのmouseover()メソッドをオーバーライドするのとは異なり、のメソッドSelectLevelをオーバーライドする必要はありません。SelectNummouseover()

SelectLevel = function(el){
    this.init(el);
    this.sup = inherit(SelectNum.prototype); //allows access to super's original methods even when overwritten in this subclass
    for(var k in this.sup){
        this.sup[k] = this.sup[k].bind(this);
    }
}
SelectLevel.prototype = inherit(SelectNum.prototype);

このコードでは、mouseover()メソッドが継続的に呼び出されます。がオブジェクトにthisバインドされたためだと思います。そのため、行では常に参照されているため、自分自身を呼び出し続けます。SelectLevelthis.supthis.sup.mouseover()SelectNumSelectNum

this.sup[k] = this.sup[k].bind(this);でバインディングを削除するとSelectLevel、エラーが発生しますUncaught TypeError: Cannot call method 'mouseover' of undefined。はthis.sup.mouseover()継続的に呼び出さmouseoverれ、プロトタイプ チェーン内の各オブジェクトでメソッドを呼び出しているようです。に達するとObject、このエラーがスローされます。もちろん、 にはプロパティObjectがないためです。sup

this.sup[k] = this.sup[k].bind(this);のバインディングを削除し、メソッドを呼び出す前に最初にプロパティをチェックする if ステートメントで をSelectLevelラップすることで、これを解決できるようです。this.sup.mouseover()supmouseover()if(this.sup !== undefined)

最終的に、JavaScript でサブクラス化する方法について、何か基本的なことが欠けていると思います。これらの特定の問題に対する解決策は、プロトタイプの継承が JS でどのように機能するかを明らかにしますが、より広いレベルでよりよく理解する必要があると本当に思います。

4

1 に答える 1

2

this.sup.mouseover();

.mouseoverオブジェクトのメソッドを呼び出しますthis.sup。あなたが欲しいのは

this.sup.mouseover.call(this)

あなたはそれを呼びたくないthis.supのですthis

それが面倒な場合は、コンストラクターで次のことを行うことができます

this.sup = inherit(Select.prototype);
for (var k in this.sup) {
  if (typeof this.sup[k] === "function") {
    this.sup[k] = this.sup[k].bind(this);
  }
}

これは基本的に、すべてのメソッドを同じ関数でオーバーライドすることを意味しますが、値thisを期待/必要なものにハードバインドします。

于 2011-10-20T14:58:52.370 に答える