js的继承方式
1.原型链继承
// 原型链继承 重点 子类的原型 = 父类的实例
function Parent(){
this.name = 'parent'
}
Parent.prototype.SayHi = function (){
console.log('我是父类上的公共方法')
}
function Child(){
this.age = '18'
}
Child.prototype = new Parent()
let child1 = new Child()
child1.name = 'child1修改了'
let child2 = new Child()
//原型链继承的方式可以复用父类原型上面的公共方法
child1.SayHi() // 我是父类上的公共方法
//下面的修改的是实例修改了父类的基础类型,不会受到影响
console.log(child1.name) // child1修改了
console.log(child2.name) // parent
// 修改一下Parent构造函数的内容
function Parent(){
this.name = ['parent']
}
Parent.prototype.SayHi = function (){
console.log('我是父类上的公共方法')
}
function Child(){
this.age = '18'
}
Child.prototype = new Parent()
let child1 = new Child()
child1.name.push('child')
let child2 = new Child()
//原型链继承的方式可以复用父类原型上面的公共方法
child1.SayHi() // 我是父类上的公共方法
//下面的修改的是child1实例修改了父类的引用类型,child2也受到了影响
console.log(child1.name) // ['parent', 'child']
console.log(child2.name) // ['parent', 'child']
// 会影响到父类实例吗? 不会!
let par = new Parent()
console.log(par.name) // ['parent']
原型链继承的优缺点
优点:通过将子类的原型设置为父类的实例进行继承,书写简单易用。
缺点:父类的引用类型会被所有的子类实例共享,并且无法向父类构造函数传递参数。
2.构造函数继承
// 构造函数继承 重点就是应用call、apply来改变this指向,达到子类构造函数中调用父类构造函数进行继承
function Parent(name){
this.name = name
}
Parent.prototype.sayHi = function (){
console.log(`hi ${this.name}`)
}
function Child(name,age){
Parent.call(this,name)
this.age = age
}
let child1 = new Child('小李',20)
let child2 = new Child('小张',18)
console.log(child1.name) // 小李
console.log(child2.name) // 小张
//Parent 原型上面的公共方法无法被子类实例使用
child1.sayHi() // Uncaught TypeError: child1.sayHi is not a function
构造函数继承的优缺点
优点:可以传递参数给父类构造函数了
缺点:无法复用父类原型的方法了,并且每次创建子类实例时都会调用一次父类构造函数
3.组合继承
// 组合继承 继承方式是 原型链继承和构造函数的合并,同时也继承了两种继承方式的优点。
function Parent(name,age){
this.name = name
this.age = age
this.inSay = function(){
console.log(`你好,我叫${this.name},我${this.age}岁了`)
}
}
Parent.prototype.sayHi = function(){
console.log(`hi,${this.name}`)
}
function Child(name,age){
Parent.call(this,name,age)
}
Child.prototype = new Parent()
let child1 = new Child('小李',17)
let child2 = new Child('小张')
child1.inSay() // 你好,我叫小李,我17岁了
child1.sayHi() // hi,小李
child2.sayHi() //hi,小张
组合继承的优缺点
优点:可以向父类构造函数传参了,也可以复用父类构造函数原型的方法了。
缺点:需要调用两次父类的构造函数。
4.原型式继承
// 原型式继承 复制一个原型对象来继承
// 也可以用 内置方法 Object.create()来代替
function fun(obj){
function Child(){}
Child.prototype = obj
return new Child()
}
let parent1 = {
name : '小李',
age:[19,20]
}
let child1 = fun(parent1)
child1.age.push(30)
let child2 = fun(parent1)
console.log(child1.age) //[19, 20, 30]
console.log(child2.age) //[19, 20, 30]
console.log(child1.name) // 小李
原型式继承的优缺点
优点:方便,可以通过Object.create()创建一个基础对象
缺点:不能传参,父类的引用类型被会被共享
5.寄生式继承
// 寄生式继承 在原型式继承的基础上,增加方法来实现继承
//这边用Object.create()来写
function createChild(obj,name){
const child = Object.create(obj)
child.age = 18
child.name = name
return child
}
const Parent ={
name : '小李'
}
let child1 = createChild(Parent,'xixi')
console.log(child1.age) //18
console.log(child1.name)
寄生式继承的优缺点
优点:可以在不改变原始对象的基础上,新增属性和方法。
缺点:不可以传参
寄生组合式继承 (最优的继承方式)
// 寄生组合式继承 在组合继承的基础上 使用寄生式继承
// 用构造函数继承属性,用寄生式继承和原型链继承父类原型
function Parent (name) {
this.name = name
}
Parent.prototype = {
saySet:function(){
console.log('set')
}
}
function Child (name){
Parent.call(this,name)
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
let child1 = new Child('xixi')
console.log(child1.name)
child1.saySet()
es6 类继承的方式
// es6 类继承的方式 Animal是一个基类 Dog继承自Animal 在子类的constructor中调用super来调用父类的构造函数,你可以在子类中去增加属性和方法。
class Animal {
constructor(name){
this.name = name
}
say(){
console.log('es6的继承方式了')
}
}
class Dog extends Animal {
constructor(name,color){
super(name)
this.color = color
}
}
const myDog = new Dog('fxx','黄色')
console.log(myDog.name)
console.log(myDog.color)
myDog.say()