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继承其他的几种方式,总结不易,要是能得到你们的点赞,就一切都值了!

浙公网安备 33010602011771号