原型继承大概是javascript中古老又传统的继承方法了,通过prototype,即可实现继承,具体的用法我在之前的文章中也提到过。
所谓原型继承就是利用javascript访问对象属性或者方法时候会查找原型链这个特性,当你创建父类对象且实例赋值给子类构造函数的原型属性,子类的实例在创建时候都会通过__proto__查找然后与子类构造函数.prototype的链接获得父类对象的所有属性和方法。这里要注意的是子类对象只是从父类继承,这些属性和方法并不真正的直接存在本身上,而是存在其构造函数的原型prototype对象中或者实例的__proto__属性上。
var Eat = function(){
this.food = “面包”;
};
var Person = function(){
this.name = name;
this.action = function(){
alert(“打完球感觉很饿,”+ “this.name” +“去商场买了”+ “this.food”);
}
};
Person.prototype = new Eat();
var person = new Person (“小明”);
person.action();
输出:打完球感觉很饿,小明去商场买了面包
当Person实例person调用action()方法时候,需要找到this.food,但是本身对象里没有这个属性,于是javascript就利用自身特性,沿着原型链查找,当查找到person的构造函数Person的prototype对象时候,发现了这一属性并返回结果。
但是原型继承并非完美的,构造函数的prototype在创建时候并非是完全的空对象,它里面是有一个属性construcor,指的是它自己,如果用一个实例对象来替换函数的prototype,那这个属性会被替换,原本的constuctor属性也随之丢失。
this.prototype ={construcor :this}
拿上面的例子来说:
输出person的constructor:
function (){
this.eat = “food”;
}
是Eat的构造函数,Person的prototype会被Eat实例替换,那里面constructor属性也被覆盖。所以,如果需要保留真正的构造器,你可以在替换了Person的prototype之后再做些别的事情:
Person.prototype.constructor = Person;
这样再访问person的constructor属性时候会反回Person的构造函数;
当构造器的prototype对象更新时候,之前产生的所有实例对象也会做出立即更新:
var Eat = function(){
this.food = “面包”;
};
var Person = function(){
this.name = name;
this.action = function(){
alert(“打完球感觉很渴+ “this.name” +“去商场喝了”+ “this.drinks);
}
};
Person.prototype = new Eat();
var person = new Person (“小明”);
person.action();
Person.prototype.drinks =“可乐”;
person.action();
先后输出:
打完球很渴,小明去商场喝了undefined
打完球很渴,小明去商场喝了可乐
很容易看出来:
Person.prototype.drinks = “可乐”
作用等于
Eat.prototype.drinks = “可乐”
这仅仅是更新,而非把prototype换成别的对象。