-
原型链:
利用原型让一个引用类型继承另一个引用的属性和方法。
构造函数中有prototype属性,指向他的原型对象,每个原型对象中也相应的有个constructor属性,指向原构造函数。
通过构造函数创建的新对象中都有一个无法直接访问的[[proto]]属性,使得该对象也指向构造函数的原型。使得对象也获得了原型中的方法和属性。当访问对象中的方法和属性时,如果对象中没有该方法和属性,则会向上一级原型对象中寻找该方法和属性,如果找到了就返回该方法和属性,如果没有,则继续向上面的原型中去查找该方法和属性,直到找到为止。
默认顶端原型:
是当所有类型都没有指明继承某个类型时,则默认继承Object类型;
- object中也有prototype属性,指向他的原型,object中也有[[proto]],只不过它指向的是null,可以忽略;
- object的很多方法,都存在object的原型中;
- 在原型链中查找,从当前位置一直往上访问,直到原型链顶端位置。
-
原型链继承
function Animal(){
this.name="动物";// 属性
this.eat=function(){ // 实例方法
return this.name+"正在吃饭!";
}
}
Animal.prototype.color="pink";// 原型属性
Animal.prototype.sit=function (){// 原型方法
return this.name+"正准备坐下!";
};
//声明一个子类
function Dog(){}
//原型链继承 直接原型一个父类 核心:将父类的实例作为子类的原型
Dog.prototype=new Animal();
//直接输出就是undefined
var dog=new Dog();
/* console.log(Dog.eat());//提示eat不是一个函数
console.log(this.eat());*/
console.log(dog.name);//动物
console.log(dog.eat());//动物正在吃饭
console.log(dog.color);//pink
console.log(dog.sit());//动物正准备坐下
Dog.prototype.type="犬类";
Dog.prototype.name="小狗";
Dog.prototype.color="red";
console.log(dog.type);//犬类
console.log(dog.name);//小狗
console.log(dog.color);//red
console.log(dog.eat());//小狗正在吃饭
console.log(dog.sit());//小狗正准备坐下
console.log(dog instanceof Dog);//true dog是Dog的一个实例化
console.log(dog instanceof Animal);//true dog是Animal的一个实例化
/* 特点:
非常纯粹的继承关系,实例是子类的实例,也是父类的实例
父类新增原型方法/原型属性,子类都能访问到
简单,易于实现
缺点:
要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
无法实现多继承
创建子类实例时,无法向父类构造函数传参*/
-
实例继承
function Animal(){
this.name=name||"猫";
this.eat=function(){
return this.name+"正在吃东西!";
}
}
Animal.prototype.sit=function(){
return this.name+"正在准备坐下!";
};
function Cat(){
var mao=new Animal();
mao.name="小猫";//先是以小猫为主,其次为猫this.name=name||"猫";
return mao;
}
var cat=new Cat();// var cat=new Animal();
console.log(cat.name);
console.log(cat.eat());
console.log(cat.sit());
/* 特点:
不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
缺点:
实例是父类的实例,不是子类的实例
不支持多继承*/
-
构造函数继承
/*替换对象*/
/*call apply*/
/*用法一致 传递的参数不一样 apply(object,[]) call(object,x1,x2,x3....)*/
/*构造继承*/
//核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
function Animal(name,age,sex){
this.name=name;
this.age=age;
this.sex=sex;
this.eat=function(){
return this.name+"正在吃东西!";
}
}
//实现多继承Type,Animal
function Type(type){
this.type=type;
this.bite=function (){
return "咬人!"
}
}
/*Type.prototype.bite=function (){
return "咬人!"
}*/
function Dog(name,age,sex,type){
Animal.call(this,name,age,sex);
Type.apply(this,[type]);//Type.apply(this,arguments);//不能实现
/* Animal.call(this);//同上效果
Type.apply(this);
this.name=name;
this.sex=sex;
this.age=age;
this.type=type;*/
}
var dog=new Dog("小狗",13,"女","犬类");
console.log(dog.name);
console.log(dog.age);
console.log(dog.sex);
console.log(dog.eat());
console.log(dog.type);
console.log(dog.bite());
console.log(dog instanceof Dog);//true dog是Dog的一个实例化
console.log(dog instanceof Animal);//false
/* 特点:
创建子类实例时,可以向父类传递参数
可以实现多继承(call多个父类对象)
缺点:
实例并不是父类的实例,只是子类的实例
只能继承父类的实例属性和方法,不能继承原型属性/方法
无法实现函数复用,每个子类都有父类实例函数的副本,影响性能*/
-
组合继承
//组合继承 重要
function Animal(name){
this.name=name;
this.eat=function(){
return this.name+"正在吃东西!";
}
}
Animal.prototype.sit=function(){
return this.name+"正在准备吃东西!";
};
//构造函数
function Dog(name){
Animal.apply(this,arguments)
}
Dog.prototype=new Animal();//同指同一个原型 使dog能够调用原型中sit方法
var dog=new Dog("猫");
console.log(dog.name);
console.log(dog.eat());
console.log(dog.sit());
/* 特点:
弥补了方式 构造函数的缺陷
缺点:
生成了两个实例,消耗内存;*/