ES5
推荐使用寄生组合继承方式
ES6
直接使用Class
的extends
即可
原型继承
优点:
- 由于方法定义在父类的原型上,复用了父类构造函数原型上的方法
缺点:
- 创建的子类实例不能传参。
- 子类实例共享了父类构造函数的引用属性(如:
arr
)
var person = {
stu:["x", "y", "z"]
}
var p1 = Object.create(person)
p1.stu.push("A")
console.log(person.stu)
借助构造函数实现继承
通过改变 Father
构造函数运行时 this
指向,指向 Son
,但是 Father
原型链上的东西没有继承
因此,通过构造函数来实现的继承,只能继承父类构造函数的属性,如果原型 prototype
上面还有方法甚至原型链上的方法,不会继承
function Father(name){
this.name = name;
this.type = ["x","y","z"]
}
Father.prototype.sayName = function(){
console.log(this.name)
}
function Son(name, age) {
Father.call(this, name);
this.age = age;
}
const son1 = new Son('wmm', 18)
console.log(son1);
console.log(son1.name, son1.age, son1.sayName) // wmm 18 undefined
借助原型链实现继承
当我们修改某一个对象时,该函数所产出的所有新实例都会发生改变,这就造成了 数据污染 问题,肯定不是我们想要的。
(因为它们引用的是同一个父类实例对象)
function Father(name) {
this.name = name || 'wmm'
this.type = ["x","y","z"]
}
function Son(age) {
this.age = age
}
Son.prototype = new Father()
let son1 = new Son(18)
let son2 = new Son(20)
son1.type.push(100)
console.log(son1.type, son2.type) // ["x", "y", "z", 100] ["x", "y", "z", 100]
组合继承
优点:
- 可传参: 子类实例创建可以传递参数。
- 方法复用: 同时所有子类可以复用父类的方法。
- 不共享父类引用属性: 子类的改变不会引起父类引用类型的共享
缺点:
- 组合继承调用了两次父类的构造函数,造成了不必要的消耗
function Father(name) {
this.name = name
this.type = ["x","y","z"]
}
Father.prototype.sayName = function() {
console.log(this.name)
}
function Son(name, age){
Father.call(this, name)
this.age = age
}
Son.prototype = new Father()
// Son.prototype.constructor指向Father
// 因此我们需要手动纠正,将Son.prototype对象的constructor值改为Son
Son.prototype.constructor = Son
//优点一:可传参
var son1 = new Son("wmm", 18)
var son2 = new Son("wmm66", 20)
//优点二:共享父类方法
son1.sayName() // wmm
son2.sayName() // wmm66
//优点三:不共享父类引用类型
son1.type.push("Q")
console.log(son1.type) // [ 'x', 'y', 'z', 'Q' ]
console.log(son2.type) // [ 'x', 'y', 'z' ]
寄生组合继承
ES5
继承的最佳方式
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的形式来继承方法。
只调用了一次父类构造函数,效率更高。避免在子类.prototype
上面创建不必要的、多余的属性,与其同时,原型链还能保持不变。
核心思想: 组合继承 + 原型继承结合两者的优点。
function Father(name){
this.name = name
this.type = ["x","y","z"]
}
Father.prototype.sayName = function(){
console.log(this.name)
}
function Son(name, age){
Father.call(this, name)
this.age = age
}
Son.prototype = Object.create(Father.prototype)
Son.prototype.constructor = Son
var son1 = new Son("wmm", 18)
var son2 = new Son("wmm66", 20)
son1.sayName() // wmm
son2.sayName() // wmm66
son1.type.push("Q")
console.log(son1.type) // [ 'x', 'y', 'z', 'Q' ]
console.log(son2.type) // [ 'x', 'y', 'z' ]
ES6的extend继承
ES6
的 extend
继承其实就是寄生组合式继承的语法糖
核心思想:
extends
: 内部相当于设置了Son.prototype = Object.create(Father.prototype)
;super()
: 内部相当于调用了Father.call(this)
小结:
- 子类只要继承父类,可以不写
constructor
,一旦写了,则在constructor
中的第一句话必须是super
- 把父类当做普通方法执行,给方法传递参数,让方法中的
this
是子类的实例
function Father(name){
this.name = name
this.type = ["x","y","z"]
}
Father.prototype.sayName = function() {
console.log(this.name)
}
class Son extends Father{
constructor(name, age) {
super(name)
this.age = age
}
}
var son1 = new Son("wmm", 18)
var son2 = new Son("wmm66", 20)
son1.sayName() // wmm
son2.sayName() // wmm66
son1.type.push("Q")
console.log(son1.type) // ["x", "y", "z", "Q"]
console.log(son2.type) // ["x", "y", "z"]
发表评论