其他分享
首页 > 其他分享> > 继承

继承

作者:互联网

1.继承

继承分为:接口继承,实现继承,在js中只要实现继承,实现继承主要依靠原型链来做到的。

定义:利用原型链让一个对象拥有另一个对象的属性和方法。

让一个构造函数的原型对象等于另一个构造函数的实例

function Fn1(){ this.num=100; } Fn1.prototype.getNum=function(){ console.log(this.num) }; var fn1=new Fn1();
function Fn2(){}; Fn2.prototype=new Fn1(); var fn2=new Fn2();
console.log(fn2.getNum()) //100 console.log(fn2.__proto__) //Fn1 {num: 100} console.log(fn1.__proto__) //{getNum: ƒ, constructor: ƒ} console.log(Fn1.prototype) //{getNum: ƒ, constructor: ƒ}
console.log(Fn1.prototype==fn1.__proto__) //true
console.log(Fn2.prototype.__proto__==fn1.__proto__) //true console.log(fn1.__proto__==Fn1.prototype) //true
console.log(Fn2.prototype.__proto__==Fn1.prototype) //true
1.每个构造函数都有一个原型对象(prototype) 2.每个原型对象都包含一个指向该构造函数的constructor属性 3.每个new出来的实例都包含一个指向原型对象的隐式原型(__proto__)属性

2.构造函数的进阶应用

  1. 从实例化的过程来看,每个实例化对象的属性大多情况下都是不同的,所有大多数属性是可变的,定义在构造函数里面的属性优先级较高,所以实例化对象可以快速访问使用构造函数中的属性。
  2. 可以通过实例对象来访问保存在构造函数原型对象上的值,但是不能通过实例对象来重写原型上的值,如果一个实例对象修改了一个原型上的属性,其他实例对象在去访问这个实例属性的时候,这个实例属性就不是以前的实例属性了。
  3. 方法大多数情况下都是固定的,因此不必每次实例化的时候都把所有的方法实例化复制一遍。
  4. 构造函数的继承是依托于原型链来完成的,而在原型链中,构造函数的原型对象大多数情况下都是用来共享方法的,当然也可以共享一些衡邵改变的共享共用属性。
  5. 每次实例化都可以得到一个构造函数实例属性的副本,同时又可以共享着共用的方法,这样可以最大限度的节省内存。同时构造函数中的属性也支持床底参数来动态修改
function Fn1(name){
    this.name=name;
    //this.getName=function(){}   //可以这样写--但不建议--原因3
}
//Fn1.prototype.name='1111';  //可以这样写--但不建议--原因2
Fn1.prototype.getName=function(){
    console.log(this.name)
}

var fn1=new Fn1('2222').getName();  //2222
var fn2=new Fn1('3333').getName();  //3333

构造函数与原型组合使用的方式,在js组件化开发过程中是最通用用到的组件化开发方式

3.继承的方式

  1. 创建一个空对象,
  2. 把实例对象的隐式原型__proto__指向构造函数的原型prototype(实例对象拥有了构造函数prototype原型对象上的属性和方法)
  3. 把构造函数的this指向替换成实例对象,再执行构造函数,(实例对象拥有了构造函数的属性和方法)
  1. 借用构造函数

      原理:子类型构造函数的内部调用父类型构造函数

    优点:1.子类可以继承父类构造函数中的属性  2.可以给父类构造函数中传递参数

    缺点:子类没办法继承父类构造函数原型上的方法

function Fn1(name){
    this.name=name;
    this.num=100;
}
Fn1.prototype.getName=function(){
    return this.name
}
function Fn2(name){
    Fn1.call(this,name);
    this.job='work'
}

var fn2=new Fn2('name');
console.log(fn2)   //Fn2 {name: "name", num: 100, job: "work"}

   2.组合继承

    原理:利用原型链实现对原型属性和方法的继承,同时通过借用构造函数来实现子类对父类构造函数内部属性的继承(先用借用构造函数的形式让子类继承父类构造函数的属性,再用原型链让子类继承父类原型对象的方法)

    优点:子类可以继承父类构造函数原型上的方法

    缺点:1.会调用2次父类构造函数(一次构建子类原型对象,一次子类构造函数内部构建子类属性)

function Fn1(name){
    this.name=name;
    this.num=100
}
Fn1.prototype.getName=function(){
   console.log(this.name)
}
function Fn2(name){
    Fn1.call(this,name)    //借用构造函数继承属性
    this.job='work'
}
Fn2.prototype=new Fn1();   //使用原型链继承方法
Fn2.prototype.constructor=Fn2;   //非必写--为了修正子类原型对象的constructor的属性
Fn2.prototype.getName=function(){
  console.log(this.name+'-22')
} var fn2=new Fn2('name2'); fn2.getName(); //name2-22 console.log(fn2) //Fn2 {name: "name2", num: 100, job: "work"}

//console.log(fn2 instanceof Fn2) //true
//console.log(fn2 instanceof Fn1) //true
//console.log(fn2 instanceof Array) //false
//console.log(fn2 instanceof Object) //true

//console.log(Fn2.prototype.isPrototypeOf(fn2)) //true
//console.log(Fn1.prototype.isPrototypeOf(fn2)) //true
//console.log(Array.prototype.isPrototypeOf(fn2)) //false
//console.log(Object.prototype.isPrototypeOf(fn2)) //true
//console.log(Object.isPrototypeOf(fn2)) //false

  3.原型式继承(浅拷贝)

    场景:让一个对象与另一个对象保持类似结构。    

    原理:借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型

    优点:构造函数内部和原型上的属性和方法都可以继承

    缺点:包含引用类型值的属性会共享相应的引用类型的值。

 

var obj1={
    name:'name1',
    num:[100,200],
}
//var obj2=obj1;
//console.log(obj2)   //{name: "name1", num: 100}

var obj2=Object.create(obj1);
obj2.name='name2';
obj2.num.push(300)
//console.log(obj2.name);  //name2
//console.log(obj2.num);   //[100, 200, 300]
//console.log(obj1.name); //name2
//console.log(obj1.num);   //[100, 200, 300]

var obj3=Object.create(obj1);
obj3.name='name3';
obj3.num.push(400)
console.log(obj3.name);   //name3
console.log(obj3.num);   //[100, 200, 300, 400]
console.log(obj2.name);  //name2
console.log(obj2.num);  //[100, 200, 300, 400]
console.log(obj1.name);   //name1
console.log(obj1.num);   //[100, 200, 300, 400]

 

  4.寄生式继承

    原理:定义一个独立的函数,在这个函数内部以某种方式来增强参数对象,在增加对象之后再返回对象

var obj1={
    name:'name1',
    num:100,
}
function hanceObj(obj){
    var newObj=Object.create(obj);
    newObj.setObj=function(){
        console.log('23234')
    }
    return newObj;
}
var obj2=hanceObj(obj1);
console.log(obj2) 
 //{setObj: ƒ} { __proto__:{name: "name1" num: 100}}

  5.寄生组合继承

    原理:让第三方构造函数来寄生父类的原型,在子类构造函数内部使用父类.call(子类的实例)改变父类的构造函数的this指向

    优点:1.解决组合继承调用2次父类构造函数的问题  2.节约内存开销

function Fn1(name){
    this.name=name
}
Fn1.prototype.getName=function(){
    console.log(this.name)
}

function Fn2(name){
    Fn1.call(this,name);
}

hanceObj(Fn2,Fn1);

function hanceObj(f2,f1){
    var prototype=Object.create(f1.prototype);
    prototype.constructor=f2
    f2.prototype=prototype;
}

var fn2=new Fn2('name222');
fn2.getName()    //name222

 

标签:构造函数,console,log,Fn1,继承,prototype,name
来源: https://www.cnblogs.com/susu2020/p/16372339.html