js继承

1原型链继承

 原型链继承:通过让子类的原型等于父类的实例,来实现继承

//父类
function Animal(){
   this.type = '动物'
}

//子类,继承了animal这个类
function  Dog(sex,age){
    this.sex = sex;
    this.age = age
}

Dog.prototype = new Animal()

let dog1 = new Dog('2岁','公')
console.log(dog1.type)    //动物

dog1.type = '狗'
console.log(dog1.type)   //狗   

let dog2 = new Dog('2岁','公')
console.log(dog2.type)   //  动物  原始类型改变不会影响到原型属性

 

因为Dog.prototype指向了new Animal创建的实例,new Animal的隐式原型__proto__指向了 Animal的原型对象Animal.prototype,实现原型链的继承

原型链继承的缺点:原型对象上的值如果为引用类型会导致一个实例修改原型,所有实例共享该原型的值都会被改变,

//父类
function Animal(){
   this.type = '动物'
   this.son = ['tom','alice']
}

//子类,继承了animal这个类
function  Dog(sex,age){
    this.sex = sex;
    this.age = age
}

Dog.prototype = new Animal()

let dog1 = new Dog()
console.log(dog1.son)     // ['tom','alice']
dog1.son.push('bob')
console.log(dog1.son)   //['tom','alice','tom']

let dog2 = new Dog()
console.log(dog2.son)    //['tom','alice',tom'']     引用类型会导致原型属性发生变化

 

看到这能明白了吧,dog1因为改变了父类构造函数引用类型son的值,导致dog2也跟着变化了,这不是喜当爹了吗,这怎么能行呢,肯定不行

 

2,借用构造函数

为解决原型链继承共享引用类型带来的问题,于是借用构造函数

实现原理在子类构造函数中,通过call或apply的形式,调用父类构造函数

//父类
function Animal(){
   this.type = '动物'
   this.son = ['tom','alice']
}

//子类,继承了animal这个类
function  Dog(sex,age){
    this.sex = sex;
    this.age = age
    Animal.call(this) 
}

let dog1 = new Dog('男','2岁')

console.log(dog1.son) // ['tom','alice']
dog1.son.push('bob')
console.log(dog1.son) //['tom','alice'] let dog2 = new Dog('女','1岁') console.log(dog2.son) //['tom','alice',tom'']

 一行代码,Animal.call(this) 解决原型链继承实例共享原型对象的问题

解决思路在于 :let dog1 = new Dog()时,this指向的是这个实例dog1,所以Animal.call(this)就相当于Animal.call(dog1),dog1去调用Animal时,Animal内部的this就指向了dog1

      那Animal内部this的属性都拷贝到了dog1上,和dog2互不影响

缺点:1每个实例都拷贝一份,当方法过多的时候,占用内存大,

   2方法和属性都作为了实例自己的私有变量,当需求改变,要改动其他一个方法时,之前所有的实例,他们的方法都不能及时作出更新

 

3.js继承之组合继承

 原型链继承+借用构造函数继承

方法挂载到父类的原型对象上,实现方法复用

实例化对象保存父类构造函数的属性

 function Animal() {

      this.type = '动物'

      this.son = ['tom', 'alice']

    }
    Animal.prototype.say = () => {

      console.log('我是prototype上的say方法')

    }

    Dog.prototype = new Animal()

    Dog.prototype.constructor = Dog

function Dog(sex, age) { this.sex = sex, this.age = age Animal.call(this) } let dog1 = new Dog('男','2岁') dog1.son.push('bob') console.log(dog1.son) //['tom','alice','bob'] dog1.say() //我是prototype上的say方法 let dog2 = new Dog('女','1岁') console.log(dog2.son) //['tom','alice'] dog2.say() //我是prototype上的say方法

 通过组合式继承就可以实现每个实例共享原型上方法,并且,每个实例拥有自己单独的父类构造函数属性啦

  这里可以打印两个dog实例  look look,可以看到他们继承了父类构造函数的所有属性

 

 写到这再说说,构造函数的静态成员,实例成员,静态成员无法被实例对象获取到,只能构造函数自身获取到,

构造函数内没有用this的属性和方法都是静态成员,反之则是实例成员,

 

 

//父类
function Animal(){
   this.type = '动物'      //实例属性

    this.son = ['tom','alice']    //实例属性
   
    name = 'animal'     //静态属性

     maxAge = '1000年'
}
Animal.say=()=>{
    console.log('我是静态方法')   //静态方法
}

Animal.prototype.say=()=>{
    console.log(''我是原型对象上方法)
}

//子类,继承了animal这个类
function  Dog(sex,age){
    this.sex = sex;
    this.age = age
    Animal.call(this) 
}

let dog1 = new Dog('男','2岁')

console.log(dog1.son)     // ['tom','alice']

dog1.son.push('bob')

console.log(dog1.son)   //['tom','alice']

let dog2 = new Dog('女','1岁')
console.log(dog2.son)    //['tom','alice',tom'']    

console.log(dog1.name)      
console.log(dog1.maxAge)           //undefined   实例对象无法访问静态成员

console.log(Animal.name)     //animal    静态属性name

Animal.say()                 //我是静态方法

dog1.say()                  //我是原型对象上方法

 

 

 

 

下次接着更新js继承其他的几种方式,总结不易,要是能得到你们的点赞,就一切都值了!

 

posted @ 2022-04-07 16:57  <hello>  阅读(52)  评论(0)    收藏  举报