1.原型链继承
每一个构造函数都有一个原型对象(prototype),原型对象又包含一个指向构造函数的指针,而实例又包含一个指向原型对象的指针(即__proto__),这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。如下图,person是Person的实例化对象
function Parent(){
this.name = 'aDong'
this.play = [1,2,3]
}
function Child(){
this.type = 'child'
}
Child.prototype = new Parent();
var s1 = new Child();
var s2 = new Child();
s1.play.push(4)
console.log(s1.play);//[1,2,3,4]
console.log(s2.play);//[1,2,3,4]
s1和s2共用同一个实例对象,内存空间共享
2.构造函数继承
借助call调用Parent构造函数
function Parent(){
this.name = 'aDong'
}
Parent.prototype.getName = function(){
return this.name
}
function Child(){
Parent.call(this)
this.type = 'child'
}
var c = new Child()
console.log(c);
console.log(c.getName());//报错
优化了第一种的继承方式的弊端,但是只能继承父类的属性和方法,不能继承原型属性和方法
3.组合式继承
将前面两种的继承方式结合起来
function Parent(){
this.name = 'aDong'
}
Parent.prototype.getName = function(){
return this.name
}
function Child(){
Parent.call(this)
this.type = 'child'
this.arr = [1,2,3]
}
Child.prototype = new Parent()
var s1 = new Child()
var s2 = new Child()
s1.arr.push(4)
//两个实例之间互不影响
console.log(s1.arr);[1,2,3,4]
console.log(s2.arr);[1,2,3]
console.log(s1.getName());//aDong
4.原型式继承
let Parent = {
name:'aDong',
friends:['oyfc','hzg'],
}
let child1 = Object.create(Parent);
child1.friends.push('zmk')
let child2 = Object.create(Parent);
console.log(child1.friends);//['oyfc', 'hzg', 'zmk']
console.log(child2.friends);//['oyfc', 'hzg', 'zmk']
Object.create是浅拷贝,多个实例的引用属性指向同一个内存空间,存在篡改的可能
5.寄生式继承
let Parent = {
name:'aDong',
friends:['oyfc','hzg'],
}
function clone(obj){
let clone = Object.create(obj);
obj.getFriends = function(){
return this.friends
}
return clone
}
let child1 = clone(Parent)
child1.friends.push('zmk')
let child2 = clone(Parent)
console.log(child1.friends);//['oyfc', 'hzg', 'zmk']
console.log(child2.friends);//['oyfc', 'hzg', 'zmk']
console.log(child1.getFriends());//['oyfc', 'hzg', 'zmk']
利用浅拷贝的性质,再添加一些方法,缺点和原型式继承一样
6.寄生组合式继承
这种继承方式是除class之外最优的继承方式
function clone(parent,child){
//改用Object.create可以减少组合继承中多进行一次构造的过程
child.prototype = Object.create(parent.prototype)
child.prototype.constructor = child
}
function Parent(){
this.name = 'aDong'
this.friends = [1,2,3]
}
Parent.prototype.getName = function(){
return this.name
}
function Child(){
Parent.call(this)
this.name = 'child'
}
clone(Parent,Child)
Child.prototype.getFriends = function(){
return this.friends
}
let child = new Child();
console.log(child);//Child {name: 'child', friends: Array(3)}
console.log(child.getName());//child
console.log(child.getFriends());//[1,2,3]
7.class继承
ES6新增class关键字,目的是为了消除函数的二义性!
class Parent{
constructor(){
this.name = 'aDong'
this.friends = [1,2,3]
}
getName() {
return this.friends
}
}
class Child extends Parent{
constructor(){
super()
this.friends = [4,5,6]
}
getName(){
return this.name
}
getFriends(){
return this.friends
}
}
let child = new Child()
console.log(child.getName());//aDong
console.log(child.getFriends());//[4,5,6]