最近在研究javascript原型链继承这一块碰到一个细节问题,引起了我的好奇,但是一直想不明白是为什么,请求大神解答:
function Shape(){
this.name='shape';
this.toString=function(){
return this.name;
}
}
function TwoDShape(){
this.name='2dshape'
}
function Triangle(side,height){
this.name='triangle';
this.side=side;
this.height=height;
this.getArea=function(){
return this.side*this.height/2;
}
}
Triangle.prototype=new TwoDShape();
TwoDShape.prototype=new Shape();
Triangle.prototype.constructor=Triangle;
TwoDShape.prototype.constructor=TwoDShape;
如上段代码所示,我建立了一个继承链,从Shape到TwoDShape,再由TwoDShape到Triangle,当我再执行以下代码时:
var shape1=new Triangle(10,9);
console.log(TwoDShape.prototype.isPrototypeOf(shape1));//输出false
程序输出false,我的理解,是isPrototypeOf寻找的是shape1最直接的那个原型,即Triangle.prototype,而这里TwoDShape.prototype不是其直接原型,所以输出了false;
然鹅,我在《javascript面向对象编程指南》这本书上看到的实践则恰恰相反:
书上在实现继承时是这样做的:
function Shape(){}
Shape.prototype.name='shape';
Shape.prototype.toString=function(){
return this.name;
}
function TwoDShape(){};
TwoDShape.prototype=new Shape();
TwoDShape.prototype.constructor=TwoDShape;
TwoDShape.prototype.name='2d shape';
function Triangle(side,height){
this.side=side;
this.height=height;
}
Triangle.prototype=new TwoDShape();
Triangle.prototype.constructor=Triangle;
Triangle.prototype.name='triangle';
Triangle.prototype.getArea=function(){
return this.side*this.height/2;
}
在执行了这段代码后再console.log(TwoDShape.prototype.isPrototypeOf(shape1));此时则会输出true,我不明白的,是这两种继承方式,不都是通过原型链继承吗?为什么两者在这个点上的输出会不一样呢?
我还有个问题,就是在学习javascript时常常碰到这样理解起来很匪夷所思的问题,应该怎样更好的理解这门语言呢?
关键在于__proto__或者叫[[Prototype]]和prototype是不一样的,prototype动态的改变不会改变__proto__或[[Prototype]]的改变。在new的时候实例中的__proto__已经固定
执行:Triangle.prototype=new TwoDShape()
重写了Triangle.prototype,和下面的constructor结合得到
而因为Triangle.prototype相当于TwoDShape的实例,于是Triangle.prototype的__proto__指向此时TwoDShape的原型对象。__proto__指向如下
当你执行TwoDShape.prototype=new Shape()。TwoDShape.prototype的原型被重写(和下面的结合),为
而重要的是实例中的__proto__在new 的时候已经固定,你的第二个new不会影响Triangle.prototype.__proto__的指向。你可以自己打印下,实在难写。这样写就是正确的
console.log(Triangle.prototype.__proto__.isPrototypeOf(shape1)),
而他的原型链中压根就没有Shape什么事
而下面的是先把TwoDshape和Shape做了链接,再用Triangle和TwoDShape做链接,Triangle中的链条才会有Shape,所以返回true
顺便说下prototype只有函数才有此属性,而__proto__或[[Prototype]]每一个对象都有。
简单的说下关系如下
function A(){}
var a = new A()
原理和下面的代码一样的