四种继承方式
1. 原型继承
- 示例:
var Partent=function(){
this.name="partent";
this.hello=function(){
return "Hello World";
}
}
var Child=function(){
}
Child.prototype=new Partent();
Child.prototype.name="child"
console.log(Child.prototype.name); // child
-
优点:
从instanceof关键字来看,实例既是父类的实例,又是子类的实例,看起来似乎是最纯粹的继承 -
缺点:
子类区别于父类的属性和方法,必须在Child.prototype=new Partent()这样的语句之后分别执行,无法被包装到Child这个构造器里面去
2. 构造继承
- 示例:
var Partent=function(name){
this.name=name;
this.id=id;
this.hello=function(){
return "Hello World";
}
}
var Child=function(name){
//Partent.call(this); apply()和call()的功能一样
Partent.apply(this,arguments);
this.name=name;
}
var child=new Child("child"); //child
-
优点:
可以实现多重继承,可以把子类特有的属性设置放在构造器内部 -
缺点:
使用instanceof发现,对象不是父类的实例
3. 实例继承
- 示例:
var Partent=function(){
this.name="partent";
this.hello=function(){
return "Hello World";
}
}
var Child=function(){
var child=new Partent();
child.name="child";
return child;
}
console.log(new Child().name) //child
-
优点:
是父类的对象,并且使用new构造对象和不使用new构造对象,都可以获得相同的效果 -
缺点:
生成的对象实质仅仅是父类的实例,并非子类的对象;不支持多继承
4. 拷贝继承
- 示例:
var Partent=function(){
this.name="partent";
this.hello=function(){
return "Hello World";
}
}
var Child=function(){
var partent=new Partent();
for(var i in partent){
Child.prototype[i]=partent[i];
}
Child.prototype.name="child";
}
console.log(new Child().name); //child
//console.log(Child().name); 与上句效果相同
-
优点:
支持多继承 -
缺点:
效率较低;无法获取父类不可枚举的方法
确定原型和实例的关系
可以通过两种方式来确定原型和实例之间的关系。操作符instanceof和isPrototypeof()方法
-
instanceof运算符希望左操作数是一个对象,右操作数标识对象的类。如果左侧的对象是右侧类的实例,则表达式返回true;否则返回false -
isPrototypeof()检测一个对象是否是另一个对象的原型(或者处于原型链中)
apply()和call()的使用
- 作用:
改变函数内部this的指向。this指向未来将要实例化这个函数的对象 - 示例:
function animal(name,food) {
this.name = name,
this.food = food,
this.say = function() {
console.log(name +" likes " + this.food + '.');
}
}
function rabbit(name,food) {
animal.call(this,name,food);
//animal.apply(this,arguments); 与上句效果相同
}
var Judy = new rabbit('Judy','carrot');
Judy.say();
- 区别:
apply方法传入两个参数:一个是作为函数上下文的对象,另外一个是作为函数参数所组成的数组。
call方法第一个参数也是作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组