function Rectangle(width, height){
this.width = width;
this.height = height;
}
Rectangle.prototype.getArea = function(){
return this.width * this.height;
}
function Square(size){
this.width = size;
this.height= size;
}
// Square 继承 Rectangle
Square.prototype = new Rectangle();
Square.prototype.constructor = Square;
var square = new Square(5);
console.log(square instanceof Square); // true;
console.log(square instanceof Rectangle); // true
console.log(square.getArea());
为什么 Square
继承 Rectangle
时,不是用 Square.prototype
指向 Rectangle.prototype
,而是指向 Rectangle
的对象实例?(而实际上继承就是用 Square.prototype
指向 Rectangle.prototype
)。
怪我咯2017-04-10 16:55:06
如果:
Square.prototype = Rectangle.prototype;
那么对Square.prototype.getArea的修改就会影响到Rectangle.prototype.getArea;
Square.prototype.getArea = function() {return "new";};
Rectangle.prototype.getArea // => function() {return "new";};
Square.prototype = new Rectangle();
就不会。
阿神2017-04-10 16:55:06
prototype实现继承的方式:
js中每个类都有prototype方法,他是一个原型链,如果本对象上找不到相关的方法,就会沿着这个原型链向父类,祖父类中找相关方法。
所以如果a类的prototype指向b类的实例,当a类中调用继承b类的方法的时候就会沿原型链找到b类对应的方法。
这个时候如果你把a类的prototype直接指向了b类的prototype,a类就找不到b类的方法,他去b类的父类找方法去了。
天蓬老师2017-04-10 16:55:06
可以参考《JavaScript高级程序设计》 P.163页所描述的:继承是通过将SuperType的实例赋给SubType.prototype实现的。实现的本质是重写原型对象,代之以一个新类型的实例。换句话说,原来存在于SuperType的实例中的所有方法和属性,现在也存在于SubType.prototype中了。
在你给出的例子中,可以这样理解:
Square.prototype = new Rectangle() //重写Square的原型对象(如果你不指定它的原型对象,Square这个构造函数的原型对象就是Object)为Rectangle的实例,这时Square就继承了这个实例的属性和方法(这里只继承了属性)
,而getArea()这个方法是从Rectangle这个实例的原型中继承的。
伊谢尔伦2017-04-10 16:55:06
(function () {
var cl = console.log;
//原型继承的问题:
function Animal() {
this.isAnimal = true;
this.colors = [];
};//父类
function Cat() {
this.isCat = true;
};//子类
Cat.prototype = Animal.prototype; //这样可以符合继承的要求吗?
//不可以,看下面代码:
var cat1 = new Cat();
cl(cat1.isAnimal);//undefined 猫也是动物啊,但是没有继承到Animal的isAnimal属性,继承失败
Cat.prototype = Animal; //这样可以符合继承的要求吗?
//不可以,看下面代码:
var cat2 = new Cat();
cl(cat2.isAnimal);//undefined 理由同上
Cat.prototype = new Animal(); //这样呢?
//相当于var cat3 = Object.create(new Animal());//这么写的话就不用声明Cat类了,最终结果是一致的
//基本上可以了
var cat3 = new Cat();
cl(cat3.isAnimal);//true 继承过来了
var cat4 = new Cat();
cat3.isAnimal = false;
cat3.isCat = false;
cl(cat4.isAnimal, cat4.isCat);//还是true,没有被cat3影响到
//问题还是有的,就怕父类的某个属性是引用类型
cat3.colors.push('yellow');
cl(cat4.colors);// [ 'yellow' ] 被影响到了!
//这个问题暂时不管
//上面的Animal类把属性声明放在构造函数里,这意味着Animal的属性和Animal.prototype一点关系都没有
//那么试试这样呢:
function Animal2() { };
Animal2.prototype.isAnimal = true;//把属性直接放在Animal2的原型上,因此它就有可能被继承了
Cat.prototype = Animal2;
var cat5 = new Cat();
cl(cat5.isAnimal);//undefined 还是不行
Cat.prototype = Animal2.prototype;
var cat6 = new Cat();
cl(cat6.isAnimal);//true 可以了!
//不过,Cat的原型和父类Animal2的原型混同之后,一个大问题是对Cat增加属性和方法会影响父类:
Cat.prototype.sound = 'meeeeeeeww';
//因此也会影响其他继承自父类的子类:
function Dog() { }
Dog.prototype = Animal2.prototype;
var dog = new Dog();
cl(dog.sound);//'meeeeeeeww'
//这种情况下,Cat和Dog就没有区别了,声明Dog类是毫无意义的
//上面为了增强Cat,把sound属性放在Cat的原型上,这同时就污染了父类的原型
//为了防止污染,可不可以规定sound必须放在Cat的构造函数里呢:
function Animal3() { };
function Cat2() {
this.sound = 'meeeeeeeww';
}
Cat2.prototype = Animal3.prototype;
//上面的Cat2类的sound属性不在原型上,所以不会影响到其他子类了。
//但是这么做,意味着Cat2所有自定义的属性和方法都要声明在构造函数里,这些属性和方法也无法被子类继承
//例如,猫还可以有子类“波斯猫”
function PersianCat() { }
PersianCat.prototype = Cat2.prototype;
var pcat = new PersianCat();
cl(pcat.sound);// undefined 这是显然的
//综上,使用子类.prototype = 父类.prototype来实现继承,陷阱太多,不好
//因此最终结论是,使用子类.prototype = new 父类()更好
//这种方法,可以形成继承链:
function Super() { }
Super.prototype.superName = { name: 'super' };
function Sub() { }
Sub.prototype = new Super();
Sub.prototype.subName = { name: 'sub' };
function Child() { }
Child.prototype = new Sub();
var child = new Child();
cl(child.superName, child.subName);//super sub
//对同一层次的子类不会互相影响
function Sub2() { }
Sub2.prototype = new Super();
var sub2 = new Sub2();
cl(sub2.superName, sub2.subName);//super undefined -----ok,没受到影响
})();
高洛峰2017-04-10 16:55:06
如果使用 Square.prototype.constructor = Square; 那么Square.prototype就没有了 width/height 属性,Square对象也就继承不了width/height