原型式继承:javascript根本没有类,对象从其他对象那里继承方法(成员函数),我们称之为原型式继承或者基于原型的继承。其中,其 成员函数 被继承的对象称为 原型;
一、再谈构造函数:它能让我们重用代码,但是效率如何呢?
function Dog(name,breed,weight){
this.name=name;
this.breed = breed;
this.weight = weight;
this.bark = function(){
if(this.weight > 25) alert(this.name +"says Woof!");
else alert(this.name + "says Yip!");
};
}
var fido = new Dog("Fido","Mixed",38);
var fluffy = new Dog("fluffy","Poodle",30);
var spot = new Dog("Spot","Chihuahua",10);
//每一次new 都会执行一次构造函数的代码,每执行一次构造函数的代码,都会在内存中开辟一块来存储匿名函
//数function(),然后将其地址返回。这样执行三次,相当于开辟了三块内存来存function,占用了不必要的内存。
二、原型式继承:
继承的工作原理:对对象调用方法或者属性时,如果在对象中找不到,将在原型中查找它。
重写原型:因为js总是 先在对象实例中查找属性,如果找不到,再沿着原型链上移,在原型中查找,因此,如果在对象实例中重写原型中的属性或者方法,js查找时在对象实例中找到了它,就不会费神去原型中查找了。
原型从哪里来?
Dog.prototype
如果你查看构造函数Dog,将发现它有一个prototype属性,这是一个指向原型的指针变量。
PS:js中函数也是对象,实际上,js中万物皆对象
如何设置原型?
function Dog(name,breed,weight){
this.name = name;
this.breed = breed;
this.weight=weight;
}
//设置小狗原型对象
Dog.prototype.bark = function(){
if(this.weight > 25){
console.log(this.name + "says Woof!");
}else{
console.log(this.name + "says Yip!");
}
};
//你可能会错误地认为 原型对象中的this指向原型对象,其实,原型对象的this仍然指向调用该方法的对象。
Dog.prototype.run = function(){
console.log("run!");
};
Dog.prototype.wag=function(){
console.log("Wag!");
};
var fido= new Dog("Fido","Mixed",38);
var fluffy = new Dog("Fluffy","Poodle",30);
var spot = new Dog("Spot","Chihuahua",10);
//重写原型
spot.bark = function(){
console.log(this.name+"says Woof!");
}
fido.bark();
fido.run();
fido.wag();
fluffy.bark();
fluffy.run();
fluffy.wag();
spot.bark();
spot.run();
//在代码中判断使用的属性包含在实例还是原型中
spot.hasOwnProperty("name");
//属于实例则返回true
建立原型链:
function Dog(name,breed,weight){
this.name = name;
this.breed = breed;
this.weight=weight;
//方法
this.bark = function(){
if(this.weight > 25){
console.log(this.name + "says Woof!");
}else{
console.log(this.name + "says Yip!");
}
};
this.run = function(){
console.log("run!");
};
this.wag=function(){
console.log("Wag!");
};
}
function ShowDog(name,breed,weight,handler){
Dog.call(this,name,breed,weight);
/*
call是一个内置方法,可以对任何函数调用它,Dog.call调用
函数Dog,将一个用作this的对象指针以及函数Dog的所有实参
传递给它。
形参中的this(ShowDog的对象实例的地址)将被赋值给Dog函数中的this,
这样Dog函数将被用来初始化ShowDog的实例对象。
*/
this.handler=handler;
}
//1.设置ShowDog的对象实例的原型 的原型 为一个Dog的实例对象
ShowDog.prototype = new Dog();
/*
这里没有给Dog传参,那么Dog创建的对象实例中属性值都是未定义的。
*/
//2.设置ShowDog的对象实例的原型
ShowDog.prototype.league="Webville";
ShowDog.prototype.stack =function(){
console.log("stack");
};
//3.创建对象实例
var fido= new Dog("Fido","Mixed",38);
var fluffy = new Dog("Fluffy","Poodle",30);
var spot = new Dog("Spot","Chihuahua",10);
spot.bark = function(){
console.log(this.name+"says Woof!");
}
var scotty = new ShowDog("scotty","scottish terrier",15,"Cookie");
fido.bark();
fluffy.run();
spot.wag();
scotty.stack();
scotty.run();
小狗原型并非原型链的终点,因为小狗原型是从Object派生出来的,你创建的每个原型链的终点都是Object,这是因为对于你创建的任何实例,其默认原型都是Object。
Object对象的toStirng方法常常被重写
function Robot(name,year,owner){
this.name = name;
this.year =year;
this.owner = owner;
}
var toy = new Robot("Toy",2013,"Aray");
console.log(toy.toString);//[Object]
//重写toString
Robot.prototype.toString = function(){
return this.name + "Robot belongs to"+ this.owner;
}
var toy = new Robot("Toy",2013,"Aray");
console.log(toy.toString);//[Object]
有些情况下,会自动调用方法toString,无须你直接调用它,例如,如果你使用运算符+来拼接字符串和对象,js将会自动调用toString将对象转换成字符串,再将该字符串与另一个字符串拼接起来。
console.log("Robot is:"+toy);
如果toString 被重写,这里将调用重写后的方法。