JS的六种继承方式
1.借助call / apply
// 父函数
function P(){
this.arr = [1,2,3]
}
// 子函数
function C(){
P.call(this)
}
缺点:这种继承方式子类可以继承父类的属性值,但是子类是无法继承父类存在的原型链上的方法。所以可以引出借助原型链的方式。
2.借助原型链
function P(){
this.arr = [1,2,3]
}
function C(){
}
C.prototype = new P()
console.log(C)
var c = new C()
var c2 =new C()
c.arr.push(4)
console.log(c.arr,c2.arr) / / [1,2,3,4] , [1,2,3,4]
缺点:通过打印我们可以看到2个实例的arr都发生了改变,那为什么会改变了?因为2个实例指向的是同一个原型对象。
那么还有更好的方式吗?
3.将前两种方式组合
function P(){
this.arr = [1,2,3]
}
function C(){
P.call(this)
}
C.prototype = new P()
console.log(C)
var c = new C()
var c2 =new C()
c.arr.push(4)
console.log(c.arr,c2.arr) / / [1,2,3,4] , [1,2,3]
通过控制台可以看到原先的问题解决了,但是又出现一个新的问题,P的构造函数会多执行一次,那么我们怎么去优化它呢?
4.组合继承优化1
function P(){
this.arr = [1,2,3]
}
function C(){
P.call(this)
}
C.prototype = P.prototype
var c = new C()
console.log(c) // P
什么?c的构造函数竟然是P,显然这不是我们想看到的,结果应该是C。
5.组合继承优化2
function P(){
this.arr = [1,2,3]
}
function C(){
P.call(this)
}
C.prototype = Object.create(P.prototype)
C.prototype.constructor = C
var c = new C()
console.log(c) // C
打印结果,构造函数指回到C了。这种继承方式接近于完美,也是我们最常用的组合寄生继承。