js的继承方式

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()