子类继承父类
面向对象开发
用作高级应用
一.原型继承
原型上的属性只能是共通的 (所有的对象都有,而且值是相同的)
缺点:原型属性共享 给子类原型追加方法或属性必须在原型继承之后
进行
原型继承不能实现多继承(同时继承多个对象)
优点:直接继承(比较直观) 子类的实例既是自身,也是父类
//父类
function Animal(name,sex){
this.name=name||"动物";
this.sex=sex||"性别";
this.sleep=function(){
return this.name+"睡觉";
}
}
//子类
function Cat(){
}
function Mouse(){
}
Cat.prototype=new Animal(); //将Animal的属性给Cat的原型链
Cat.prototype.eat=function(){ //追加方法或属性,在原型继承之后
return this.name+"吃饭";
}
//原型prototype写在new之前
var cat=new Cat(); //实例化对象
//cat.name="小花"; //这样写原型里边有name,外边的类对象也有name
//全部都写成prototype继承
Mouse.prototype=new Animal(222); //父里边的属性子都可以使用,传参的话,在new Animal这里传参
var mouse=new Mouse();
var mouse1=new Mouse();
console.log(cat);
console.log(mouse);//mouse和mouse1输出一样
console.log(mouse1);
console.log(cat instanceof Cat); //true
console.log(cat instanceof Animal); //true
//缺点:原型属性共享 给子类原型追加方法或属性必须在原型继承之后进行
//原型继承不能实现多继承(同时继承多个对象)
//优点:直接继承(比较直观) 子类的实例既是自身,也是父类
实例中存在和原型对象上同名的属性时,会自动屏蔽原型对象上的同名属性
只会在实例上创建一个同名的本地属性。
//父类:人
function Person () {
this.head = '脑袋瓜子';
}
//子类:学生,继承了“人”这个类
function Student(studentID) {
this.studentID = studentID;
}
Student.prototype = new Person();
var stu1 = new Student(1001);
console.log(stu1.head); //脑袋瓜子
stu1.head = '聪明的脑袋瓜子';
console.log(stu1.head); //聪明的脑袋瓜子
var stu2 = new Student(1002);
console.log(stu2.head); //脑袋瓜子
原型上任何类型的属性值都不会通过实例被重写,但是引用类型的属性值会受到实例的影响而修改。
二.构造继承
在子类的构造函数中,通过 apply () 或 call ()的形式,调用父类构造函数,以实现继承。
优点:在创建子类的实例的时候可以向父类传参
可以实现多继承
子类的实例只能是自身
call apply 对象里边的this替换
参数 1.替换的对象 2.参数列表
call(this,1,2,3,4,5) 序列参数列表 apply(this,[1,2,3,4,5]) 集合
//两个父类,多继承
function Animal(name,sex){
this.name=name||"动物";
this.sex=sex||"性别";
this.sleep=function(){
return this.name+"睡觉";
}
}
function Type(type){
this.type=type||"类别";
}
//子类
function Cat(name,sex,type){
Animal.call(this,name,sex); //这个this就是animal里边的this,相当于将Animal的东西全部复制过去
Type.apply(this,[type]);
this.eat=function(){
return this.name+"爱吃老鼠";
}
}
function Mouse(){
}
var cat=new Cat("小黑","公","猫科");
var cat1=new Cat("小百","母","狗科");
console.log(cat);
console.log(cat1);
console.log(cat instanceof Cat); //true
console.log(cat instanceof Animal); //false
//优点:在创建子类的实例的时候可以向父类传参 可以实现多继承
//子类的实例只能是自身
三.组合继承 原型+构造
可以实现多继承
子类的实例既是自身也是父类
数据共享
function Animal(name,sex){
this.name=name||"动物";
this.sex=sex||"性别";
this.sleep=function(){
return this.name+"睡觉";
}
}
function Type(type){
this.type=type||"类别";
}
function Cat(type){ //构造继承
Type.call(this,type);
}
Cat.prototype=new Animal(); //原型继承
Cat.prototype.name="小花";
var cat=new Cat(123);
console.log(cat);
console.log(cat instanceof Cat)
console.log(cat instanceof Animal)
四.实例继承
子类对象中实例化父类,然后返回父类
最大优点:不会限制我们的执行方法,可以直接new,也可以直接调用
缺点:子类的实例不是本身,而是父类; 不可以实现多继承
//父类
function Animal(name,sex){
this.name=name||"动物";
this.sex=sex||"性别";
this.sleep=function(){
return this.name+"睡觉";
}
}
//子类
function Cat(name,sex){
this.eat="fdghghdhas"; //里边并不会出现eat属性,不可以这样追加属性。
var animal=new Animal(name,sex);//追加属性,只能在父类中追加属性
return animal; //方法里边返回对象
}
var cat=new Cat("123","111");
console.log(cat); //Animal {name: "123", sex: "111", sleep: ƒ}
console.log(cat instanceof Cat); //false
console.log(cat instanceof Animal); //true 缺点:子类的实例不是本身,而是父类; 不可以实现多继承
var cat1=Cat("xnn","jsjj");
console.log(cat1);//Animal {name: "xnn", sex: "jsjj", sleep: ƒ}
//最大优点:不会限制我们的执行方法,可以直接new,也可以直接调用
五.组合寄生
构造+原型+寄生 = 组合寄生模式(好几个模式组到一起再加一个寄生)
继承的时候原型追加的方法继承不到,若是想用这个方法,只能把原型对象的方法寄生到某个东西上
Super的原型属性没办法直接继承,只能间接性的给到某一个对象的属性上,然后再通过继承,就可以用原型属性了
function Super(b){
this.b=b;
this.fun=function(){}
}
//给Super追加底层方法
Super.prototype.c=function(){
console.log(1);
}//继承的时候原型追加的方法继承不到,若是想用这个方法,只能把原型对象的方法寄生到某个东西上
function f1(){
}
var f=new f1();//将底层方法分离出来
f.prototype=Super.prototype; //将Super的原型对象寄生到f1的原型上,f1相当于一个桥
function Foo(a,b){
this.a=a;
Super.call(this,b);//构造继承
}
Foo.prototype=f;
var foo1=new Foo(1,2);
console.log(foo1);
console.log(foo1.prototype.c()); //会输出undefined,因为这个方法没有返回值
// console.log(foo1.c()); //不能直接点c,要加prototype,因为c方法在原型上
先new再寄生原型:原型方法和属性在prototype中
(先new再寄生原型:相当于给f1添加原型链)
先寄生再new原型:原型方法和属性可以直接点出来
(c方法会跑到Object原型链上,原因:f1的原型链往下直接指向Object,Object中才有prototype)
function Super(b){
this.b=b;
this.fun=function(){}
}
Super.prototype.c=function(){
console.log(1);
}
function f1(){
}
f1.prototype=Super.prototype;
var f=new f1();
function Foo(a,b){
this.a=a;
Super.call(this,b);
}
Foo.prototype=f;
var foo1=new Foo(1,2);
console.log(foo1);
console.log(foo1.c());
六.寄生模式
继承时有些模式 拿不到原型的一些方法和属性,考虑寄生
原型继承,父类添加的原型可以获取到
function Animal(name,sex){
this.name=name;
this.sex=sex;
this.eat=function(){
return this.name+"啥都吃";
}
}
function Cat(){
}
Cat.prototype=new Animal("小花","女"); //给Animal里边的属性赋值,在Animal这里传参
原型继承,父类里边的内容都是共享的
Animal.prototype.like=function(){
return "躺床上";
}
var cat=new Cat();
console.log(cat);
console.log(cat.like());
//Cat {}
__proto__: Animal
eat: ƒ ()
name: "小花"
sex: "女"
__proto__:
like: ƒ () //在Object原型链上,Animal没被new之前,Animal原型链直接指向Object
constructor: ƒ Animal(name,sex)
__proto__: Object
构造继承,父类方法的原型方法继承不到
若想拿到外边的要考虑寄生
function Animal(name,sex){
this.name=name;
this.sex=sex;
this.eat=function(){
return this.name+"啥都吃";
}
}
function Cat(name,sex){
Animal.call(this,name,sex);
}
Animal.prototype.like=function(){
return "躺床上";
}
var cat=new Cat("小花","女");
console.log(cat);//构造继承,原型追加的属性无法获得
//Cat {name: "小花", sex: "女", eat: ƒ}
eat: ƒ ()
name: "小花"
sex: "女"
__proto__:
constructor: ƒ Cat(name,sex)
__proto__: Object
添加寄生继承后,父类的原型子类就可以获取到了
只是构造模式的继承
function Animal(name,sex){
this.name=name;
this.sex=sex;
this.eat=function(){
return this.name+"啥都吃";
}
}
Animal.prototype.like=function(){
console.log(this); //这里边的this指得是Animal.prototype原型链
return this.name+ "躺床上";
}
function Cat(name,sex){
Animal.call(this,name,sex);
}
var cat=new Cat("小花","女");
cat.likeele=Animal.prototype; //原型添加到一个属性上
console.log(cat);
console.log(cat.likeele.like.call(cat));//用cat里边的this替换Animal.prototype原型里边的this