现在有parent、child两个函数,child函数的实例想要访问parent函数的属性和方法(child想要继承parent)。
1、原型链继承
缺点:有引用的值共享的问题
即当parent某个属性是引用数据类型的时候,child实例如果修改了这个属性的内容则其他的child实例中这个属性也会一起改变(正常来说应该是互不干扰的,原始数据类型属性就是互不干扰的)
function parent(){
this.data = '我是parent'
}
function child(){}
child.prototype = new parent()
var fun = new child()
console.log(fun.data)
2、构造函数继承
通过在child函数中独立执行parent( 此时parent的this指向window ),然后通过call方法改变parent的指向指向child实例( parent.call(this) ),这样new出来的child实例就能访问到parent中的属性和方法了。这种方法就称为构造函数继承。
缺点:使用这种方法child实例没有办法拿到parent函数原型上的属性和方法。
function parent(){
this.data = '我是parent'
}
parent.prototype.say = function(){
console.log("我是parent原型")
}
function child(){
parent.call(this)
}
var fun = new child()
console.log(fun.data) // 输出“我是parent”
fun.say() // 此处报错
3、组合继承(构造函数+原型链)
这个方法是结合了上述的两个方法:
- 用构造函数继承中的child函数独立执行parent来解决原型链继承的引用值共享问题
- 用原型链继承中child函数的原型指向parent的实例来解决构造函数中child实例无法访问parent原型上属性和方法的问题。
缺点:new了两次parent,会产生了属性与方法重叠的问题。
function parent(){
this.data = '我是parent'
}
parent.prototype.say = function(){
console.log("我是parent原型")
}
function child(){
parent.call(this)
}
child.prototype = new parent()
var fun = new child()
console.log(fun.data)
fun.say()
4、寄生组合继承(经典继承)
(第三种方法)组合继承:无论什么情况下,都会调用两次父类的构造函数。寄生组合式继承就解决了上述问题,被认为是最理想的继承方式。
function parent(){
this.data = '我是parent'
}
parent.prototype.say = function(){
console.log("我是parent原型")
}
function child(){
parent.call(this)
}
child.prototype = Object.create(parent.prototype)
var fun= new child()
console.log(fun.data)
fun.say()
5、原型式继承
原型式继承是一种基于已有对象创建新对象的继承方式,适用于简单对象的继承。在 JavaScript 中可以使用 Object.create
方法来实现原型式继承。
// 原型对象
var parent = {
name: 'parent',
age: 30,
say: function () {
return '我是' + this.name
}
}
// 基于原型对象创建新对象
var child= Object.create(parent)
child.name = 'Alice' // 修改属性值
child.age = 25 // 修改属性值
console.log(child.say()) // 输出 "我是 Alice"
6、es6的extends类继承
child类通过extends继承了parent类的属性和方法。
class Parent {
constructor(name) {
this.name = name
}
// 原型方法
// 即 Parent.prototype.getName = function() { }
// 下面可以简写为 getName() {...}
getName = function () {
console.log('Parent:', this.name)
}
}
class Child extends Parent {
constructor(name, age) {
// 子类中存在构造函数,则需要在使用“this”之前首先调用 super()。
super(name)
this.age = age
}
}
const asuna = new Child('Asuna', 20)
asuna.getName() // 成功访问到父类的方法