js 中 prototype 继承问题

function pp(json) {
  this.x = (json.x != null) ? json.x : '未知';
  this.xx = (json.xx != null) ? json.xx : this.x / 2;
}

function zz(x){
  this.x = x;
}

zz.prototype = new pp({});

然后

var zz = new zz(50);
alert(zz.x + '---' + zz.xx);

alert 显示的数据是 500 ,怎样才能简便的实时更新继承 ppxx 的值?我想要的是 25

求解惑


那有没有其他好的方法满足我的继承呢?

阅读 3.5k
4 个回答

我来说一下吧。按照你的代码来讲一下执行过程,先按照你的来。

首先应该是变量提升,var了一个全局zz变量,此时还是undefined,然后函数接着提升,此时,定义了一个函数pp,接着又一个函数直接覆盖了zz的值(或者叫zz这个变量的指针指向了zz这个被申明的函数对象),目前为止,一切正常。

然后给zz这个函数增加原型链,或者叫覆盖!覆盖的是一个被构造过的pp函数函数对象。这里就是错误的开始。
因为你直接给zz.prototype赋值的是一个构造函数对象,在new的过程中传进去的是一个空对象,所以当时的x已经是未知,xx就成了未知这个字符串除以2,成了NaN。然后这个新开辟的对象直接就赋值给了zz.prototype。
需要注意的是这个时候zz.prototype的值是一个已经被实例化的对象了,继续向下走程序。

继续用构造的方法来new zz,传50进去,然后,zz.x就等于了50,然后把这个构造好的对象赋值重新赋值给zz这个早已申明过的zz(或者叫做zz的指针改指向新的实例化对象)。

然后就是alert,zz.x当然是正确的,xx的时候就去找原型链了,果然找到了,一个早已生成好的NaN


下面讲一下,你想实现的东西,就是在给x赋值的时候自动更新xx的值(不知道我理解到题主的题意没有),其实非常简单,非常多种实现:
先来setter,这应该最符合题意的 https://developer.mozilla.org...

var zz = {
    set x(num){
        this._x = !num && num !==0 ? '未知' : num;
        this.xx = this._x / 2;
    },
    get x(){
        return this._x;
    }
};

zz.x = 50;
console.log(zz.x, zz.xx);

我这儿用的es6的写法,习惯了。。。题主可以用es5中的defineProperty写,反正相关文档上面给了。

再来就是楼上讲的那种最简单的构造。

function ZZ(num){
    this.x = !num && num !==0 ? '未知' : num;
    this.xx = this.x / 2;
}

var zz = new ZZ(50);
console.log(zz.x, zz.xx);

还有就是原型链xx,不过这个跑的有点偏,篡改题意了。

function ZZ(num){
    this.x = !num && num !==0 ? '未知' : num;
}
ZZ.prototype.xx = function(){
    return this.x / 2;
}

var zz = new ZZ(50);
console.log(zz.x, zz.xx());

。。不知道你是什么缘由想要更新 pp 的 x,xx ,他们虽然在 pp 函数中,但是通过 zz.prototype = new pp({}); 已经传递 zz 了,不信看图:

clipboard.png

pp 中还是 啥都没有:

clipboard.png

而通过 var z= new zz(50);(我手动帮你改成 z),这时候的 z:

clipboard.png

所有当你访问 (z.x+'---'+z.xx) 的时候,返回 50 和 NaN,如果需要得到 xx = 25,有两种方法,第一种,改变 zz 函数:

function zz(x){
    this.x= x;
    this.xx = this.x/2;
}

这个时候 的 z :

clipboard.png

第二种,用函数来实现,

function pp(json){
    this.x = (json.x!=null) ? json.x : '未知';
    this.xx = function(){
      return this.x/2;
    }
}

调用:console.log(z.x+'---'+z.xx());

不知道你的动机是什么。

我左看右看怎么看都觉得这个例子是写错的。倒推回去怎么想都不可能得到你想要的答案。

pp中的this.x先被改了,然后this.xx要变为你希望是50的一半,问题是this.xx要得出25,除非有json.x=50才有可能,因为不论你this.x是多少,最后决定this.xx多少的是json.x而不是this.x

this.x = (json.x!=null) ? json.x : '未知';
this.xx = (json.xx!=null) ? json.xx : this.x/2;

下面这一行等于让json必定是空对象,所以json.x也没了,不存在了。到pp中this.x变为未知this.xx怎么还有可能是50的一半,是'未知'/2(相当于NaN)。再用更多的技巧都不可能让this.xx有25这个值。当然直接指定25是另一回事了。

zz.prototype = new pp({});

所以,要不要再确定一下到底想作什么应用,这题我答不出来。

alert(zz.x+'---'+zz.xx);

当输出 zz.x 时实例中有这个属性,所以输出50,当输出 zz.xx 时实例中没有这个属性,所以就到原型链中去找,当找到 zz.prototype 时,其中有 xx 这个属性,因为这个属性的值用到 this.x,但是 当前函数中this.x 是 NaN,所以结果就是这样

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题