js是可以面向对象的,自然少不了继承,js实现继承的方式有好几种,这里做一些记录
原型继承
function Super(name){
this.name = name
this.color = ['red','blue']
}
Super.prototype.addColor = function(color){
this.color.push(color)
}
function Sub(){}
Sub.prototype = new Super()
Sub.prototype.constructor = Sub
let sub1 = new Sub('mike')
let sub2 = new Sub('jake')
console.log(sub1.color) // ['red','blue']
sub2.addColor('black')
console.log(sub1.color) // ['red','blue','black']
复制代码
原型继承的原理就是让子类的原型成为父类的示例,这样子类就可以共享父类的方法,需要注意重新给constructor
赋值,这种继承的缺点有两个:
- 1 无法在实例化子类时自定义构造参数
- 2 子类实例共享引用类型属性,如上所示,sub2改变color会影响sub1
构造函数继承
function Super(name){
this.name = name
this.sayName = function(){ console.log(this.name)}
}
function Sub(name){
Super.call(this,name)
}
let sub = new Sub('mike')
sub.sayName() // mike
复制代码
可以看到,构造函数继承就是将父类函数在子类中执行一遍,此时引用类型属性不再共享,构造参数可自定义,可缺点也很明显,每个子类重新创建了父类的方法,不存在共享。
组合继承
结合以上两种方法便有了组合继承
function Super(name){
this.name = name
this.color = ['red','blue']
}
Super.prototype.addColor = function(color){
this.color.push(color)
}
function Sub(name,age){
Super.call(this,name)
this.age = age
}
Sub.prototype = new Super()
Sub.prototype.constructor = Sub
let sub1 = new Sub('mike')
let sub2 = new Sub('jake')
console.log(sub1.color) // ['red','blue']
sub2.addColor('black')
console.log(sub1.color) // ['red','blue']
复制代码
父类方法在子类中共享,引用属性不共享,构造参数可自定义,ok了?这里还有一个问题,这种方法执行了两次父类构造函数,如果父类的构造函数代码特别多就不太好了。
寄生组合继承
function Super(name){
this.name = name
this.color = ['red','blue']
}
Super.prototype.addColor = function(color){
this.color.push(color)
}
function Sub(name,age){
Super.call(this,name)
this.age = age
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
复制代码
通过object.create
方法直接将Sub.prototype
链到Super.prototype
实现方法继承又不必执行一次父类构造函数,Object.create可以这样实现:
Object.create = function(obj){
function F(){}
F.prototype = obj
return new F()
}
复制代码