js的继承方式有很多,比如
一、借用构造函数继承(call,apply,bind)
1.介绍
利用call,apply,bind借用父类的构造函数
2.实现
function Animal (name) {
this.name = name
this.showName = function () {
alert(this.name)
}
}
function Cat () {
// apply用法:传参传一个数组
Animal.apply(this, [name])
}
var cat = new Cat('飞翔的哔哔鸡')
cat.showName()
// call用法:传参传一个字符串
Animal.call(this, name)
// bind用法:先调用再传参
Animal.bind(this)(name)
3.优缺点
1)优点
简单明了
2)缺点
无法继承原型链上的属性和方法
二、原型链继承
1.介绍
利用原型链来实现继承,父类的一个实例作为子类的原型,也就是 子构造函数.prototype = new 父构造函数()
2.实现
function Animal (name) {
this.name = name
this.friends = ['小狗','小猫']
this.showName = function () {
alert(this.name)
}
}
function Cat () {
}
Cat.prototype = new Animal()
// 注意这里new Animal()生成的父类对象并没有constructor属性,故需添加上
Cat.prototype.constructor = Cat
3.优缺点
1)优点
容易实现
2)缺点
//当父类中包含引用类型属性值时,其中一个子类的多个实例中,只要其中一个实例引用属性只发生修改一个修改,其他实例的引用类型属性值也会立即发生改变
//原因是父类的属性变成子类的原型属性
var cat1 = new Cat()
var cat2 = new Cat()
cat1.friends.push('小猪')
console.log(cat1.friends) //['小狗','小猫','小猪']
console.log(cat2.friends) //['小狗','小猫','小猪']
三、组合式继承(原型链继承+借用构造函数继承)
1.介绍
实际开发比较常用(当然不考虑兼容性的话我更喜欢es6的extend)
2.实现
function Animal (name) {
this.name = name
this.showName = function () {
alert(this.name)
}
}
function Cat () {
// apply用法:传参传一个数组
Animal.apply(this, [name]) //第二次调用
}
Cat.prototype = new Animal() //第一次调用
var cat = new Cat('飞翔的哔哔鸡')
cat.showName()
3.优缺点
1)优点
解决了构造继承和原型链继承的两个问题
2)缺点
父类的构造函数被调用两次,实际上子类上会拥有超类的两份属性,只是子类的属性覆盖了超类的属性
四、es6的extends
1.介绍
实际开发比较常用,写法更加面向对象,原理还是原型链
2.实现
class Animal {
constructor (name) {
this.name = name
}
showName () {
alert(this.name)
}
}
class Cat extends Animal {
constructor (name) {
super(name)
this.type = '宠物'
}
}
var cat = new Cat('飞翔的哔哔鸡')
cat.showName()
3.super关键字
super这个关键字,既可以当作函数使用,也可以当作对象使用。当作函数使用时,super代表父类的构造函数,并在子类中执行Parent.apply(this),从而将父类实例对象的属性和方法,添加到子类的this上面。以下三点需要特别注意:
1)子类必须在constructor方法中调用super方法,如果子类没有定义constructor方法,constructor方法以及其内部的super方法会被默认添加。
2)在子类的constructor方法中,只有调用super之后,才可以使用this关键字,否则会报错。
3)super作为对象时,在子类中指向父类的原型对象。即super=Parent.prototype。
例子:
class Animal {
constructor (name) {
this.name = name
}
showName () {
alert(this.name)
}
}
class Cat extends Animal {
constructor (name) {
super(name)
}
sayMy () {
super.showName()
}
}
var cat = new Cat('飞翔的哔哔鸡')
cat.sayMy() //飞翔的哔哔鸡
4.static关键字
在一个方法前加上关键字static,就表示该方法不会被实例继承,但是父类的静态方法,会被子类继承。
class Animal {
static showWhat (name) {
alert(name)
}
showName (name) {
showWhat(name)
}
}
class Cat extends Animal {}
Cat.showWhat('小猪') //小猪
var an = new Animal()
an.showWhat('小狗') //Uncaught TypeError: an.showWhat is not a function