ES5继承
在ES5中没有类的概念,所以一般都是基于原型链继承,具体的继承方法有以下几种:
父类: function Father (name) { this.name = name || ‘sam‘ this.sleep = function () { // 实例方法 return this.name + ‘正在睡觉‘ } } Father.prototype.eat = funciton () { // 原型方法 return this.name + ‘正在吃饭‘ }
一,原型链继承
核心:将父类的实例作为子类的原型
子类: function Son () { this.age = 12 } Son.prototype = new Father() Son.prototype.name = ‘Sam‘ var son = new Son() document.write(son.age) document.write(son.name) // Sam document.write(son.sleep()) // Sam正在睡觉 document.write(son.eat()) // Sam正在吃饭
优点:
(1)非常纯粹的继承关系,实例是子类的实例,也是父类的实例
(2)父类新增的属性和方法,子类都能访问到
(3)简单,易于实现
缺点:
(1)无法实现多继承
(2)来自原型对象的引用属性是所有子类实例共享的
(3)创建子类实例时,无法向父类的构造函数传递参数
二,构造继承
核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类
子类: function Son (age) { Father(this) //实现了继承 this.age = age } var son = new Son() console.log(son.name) // 返回sam console.log(son.sleep()) // 返回sam正在睡觉 console.log(son.eat()) // 报错Uncaught TypeError
优点:
(1)子类创建时,可以通过call或者apply向父类传递参数
(2)可以实现多继承(call多个父类对象)
缺点:
(1)实例并不是父类的实例,只是子类的实例
(2)只能继承父类的实例属性和方法,不能继承原型属性和方法
(3)无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
三,实例继承
核心:为父类实例添加新特性,作为子类实例返回
子类:
function Son (name) { var instance = new Father() instance.name = name || ‘Tom‘ return instance } var son = new Son() console.log(son.name) console.log(son.sleep()) console.log(son.eat())
缺点:
(1)实例是父类的实例,不是子类的实例
(2)不支持多继承
四,组合继承
核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
子类:
function Son (age) {
Father.call(this,‘sam‘)
this.age = age
}
Son.prototype = new Father()
var son = new Son()
console.log(son.name)
console.log(son.eat())
console.log(son.sleep())
优点:
(1)可以继承实例属性和方法,还可以继承原型属性和方法
(2)既是子类的实例,也是父类的实例
(3)不存在引用属性共享问题
(4)可传参
(5)函数可复用
缺点:调用了两次父类构造函数,生成了两份实例
ES6继承
ES6里面引入了类class的概念,class可以通过extends关键字实现继承,这比ES5通过修改原型链实现继承,要清晰和方便很多
父类(关于ES6中通过class定义一个实例对象的方法这里略过)
class Father { constructor (name) { this.name =name } eat () { return this.name + ‘正在吃饭‘ } sleep () { return this.name + ‘正在睡觉‘ } }
子类
class Son extends Father {
}
class Son extends Father {
constructor () {
super()
}
}
以上两种写法是相等的。如果子类中没有定义constructor,这个方法会被默认添加,不管有没有显示定义,任何一个子类都有constructor方法。
子类 class Son extends Father { constructor (color) { this.color = color } } var son = new Son console.log(son.color) // 报错
在子类的构造函数中,如果用了constructor方法,则必须调用super方法。只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,是基于对父类实例的加工,只有super方法才能返回父类实例
class Son extends Father { constructor (name,age) { super (name) this.age = age } play () { return super.eat()+ ‘正在玩耍‘ } } var son = new Son(‘sam‘) console.log(son.play())