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 at 时创建的内容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

无法按您的预期工作。您似乎想更改通过调用超级构造函数创建的变量(它仍然是该变量环境的本地变量,并且由在构造函数中创建的getTand函数公开。所以现在,您正在调用在该行- 更改在那里创建的变量。您当前对象上的函数无关紧要,因为它不使用内部关键字。setTECar.prototype = new Car();tcallthis

因此,您不想 a) 使用该原型 Car 的方法,但您自己的方法和 b) 根本不想Car为原型创建实例。另请参阅[不]在此处使用“新”关键字的原因是什么?. 在当前实例上应用超级构造函数就足够了。如果您想在仍然使用旧方法的同时扩展方法,则需要将它们(并且确切地说是它们)保存在变量中。

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 回答