4

重複の可能性:
JSオブジェクトのプロパティが他のインスタンスによって上書きされるのはなぜですか

setTが呼び出された後、属性「t」が変更されないのはなぜですか?出力として「4」を期待しますが、「デフォルト」と出力されます。

function Car(i) {
  var id = i;
  var t = "default";

  this.getT = function() { return t; }
  this.setT = function(p) {
    t = p;  // attribute t isn't changed ..
  }
}

function ECar(id) {  
  Car.call(this, id);  // super constructor call

  this.setT = function(p) {  // override
    ECar.prototype.setT.call(this, p); // super call
  }
}

ECar.prototype = new Car();

ecar = new ECar(3);
ecar.setT(4);
alert(ecar.getT()); // prints default, not 4
4

3 に答える 3

4

ECar.prototype = new Car();

この行ECarで、プロトタイプはコンテキストを取得します。このコンテキストでは、すべてECarのインスタンスが共有されます。

ECar.prototype.setT.call(this, p);

この行は、 superを呼び出しているときに作成されたものではなく、そのコンテキストで呼び出します。Car.call(this, id);

あなたはであなたのコードを修正することができます

function ECar(id) {  
  Car.call(this, id);  // super constructor call
  var carSetT = this.setT;
  this.setT = function(p) {
    carSetT.call(this, p);
  }
}

しかし、次のような実際のプロトタイプを使用する方が良い(そして読みやすい)でしょう。

function Car() {}

Car.prototype.getT = function () { /* ... */ };
Car.prototype.setT = function () { /* ... */ };

function ECar() {}

ECar.prototype = new Car();
ECar.prototype.setT = function () { /* ... */ };

編集メモ(@Bergiが提案したように)

レガシーブラウザをサポートする必要がある場合にのみ継承Child.prototype = new Parent()として使用する必要があります。その後、空のコンストラクタのみを使用する必要があります。

継承のためのJavaScriptで最も(他の言語の)互換性のある方法は

Child.prototype = Object.create(Parent.prototype)

MDNは、IE 9からサポートされていると言っています)

于 2012-10-31T21:30:28.907 に答える
2

// attribute t isn't changed ..

tこれは「属性」ではなく、コンストラクタースコープにローカルな変数(「プライベート」)であることに注意してください。

ECar.prototype.setT.call(this, p); // super call

期待どおりに機能しません。スーパーコンストラクターの呼び出しで作成された変数を変更したいようです(それはまだその変数環境に対してローカルであり、コンストラクターで作成された関数getTと関数によって公開されます。したがって、ここで作成された関数を呼び出しています。行-そこで作成された変数を変更します。現在のオブジェクトの関数は、内部でキーワードを使用しないため、重要ではありません。setTECar.prototype = new Car();tcallthis

したがって、a)そのプロトタイプCarのメソッドを使用する必要はありませんが、b)Carプロトタイプのインスタンスを作成する必要はありません。ここで「new」キーワードを使用する[しない]理由は何ですか?も参照してください。。現在のインスタンスにスーパーコンストラクターを適用するだけで十分です。古いメソッドを使用したままメソッドを拡張する場合は、それら(および正確にそれら)を変数に保存する必要があります。

function Car(id) {
    var t = "default";
    this.getT = function () {
        return t;
    };
    this.setT = function (p) {
        t = p;
    };
}

function ECar(id) {
    Car.call(this, id); // super constructor call

    var oldSetter = this.setT;
    this.setT = function (p) { // override
        oldSetter(p); // call the function which access this instance's "t"
    }
}
ECar.prototype = Object.create(Car.prototype, {constructor: {value: ECar}});

var ecar = new ECar(3);
ecar.setT(4);
console.log(ecar.getT()); // prints 4
于 2012-10-31T21:29:48.413 に答える
0
function Car(i) {
   var id = i;
   var t = "default";

   this.getT = function() { return t; }
   this.setT = function(p) {
      t = p;  // attribute t isn't changed ..
   }
}

 function ECar(id) {  
     Car.call(this, id);  // super constructor call
 }

ECar.prototype = new Car();
ECar.prototype.constructor = ECar;  //Never forget doing this
ecar = new ECar(3);
ecar.setT(4);
alert(ecar.getT());

setT関数をオーバーライドする必要はありません。</ p>

于 2012-10-31T21:19:05.450 に答える