js基础的面向对象的继承
构造函数继承
function Parent() {
this.name = 'parent'
}
function Child() {
Parent.call(this) //原理就是调用parent并且改变this的指向,指向当前的this
this.type = 'child'
}
这种方法的缺陷是只会继承构造函数上的实例属性,并不会继承原型对象上的属性,优点就是如果parent上有引用类型的属性,不会共用
借助原型链继承
function Parent() {
this.name = 'parent'
}
Parent.prototype.say = function () {
console.log('say hello');
}
function Child() {
this.type = 'child'
}
Child.prototype = new Parent //通过原型链继承把实例上的属性和原型上的属性都继承了
缺点就是如果原型上的属性有引用类型的,改变了其中一个实例上的引用属性,另外一个也会改变,
构造函数加原型链的继承方式
function Parent() {
this.name = 'parent'
this.arr = [1,2,3]
}
Parent.prototype.say = function () {
console.log('say hello');
}
function Child() {
Parent.call(this) //继承parent构造函数里面的方法
this.type = 'child'
}
Child.prototype = new Parent //继承构造函数parent原型上的方法
这个综合了两种方法比较完美,但是parent构造函数执行了两次,只是不必要的,也是对资源的一种浪费,稍微优化下就好了
function Parent() {
this.name = 'parent'
this.arr = [1,2,3]
}
Parent.prototype.say = function () {
console.log('say hello');
}
function Child() {
Parent.call(this) //继承parent构造函数里面的方法
this.type = 'child'
}
Child.prototype = Parent.prototype//继承构造函数parent原型上的方法
这里还有个小缺陷,因为Child的原型和Parent的原型是同一个对象,所以constructor都会指向parent,所以就不能区分child构造出来的实例到底是由Child构造的还是Parent构造的
于是还可以优化一下
function Parent() {
this.name = 'parent'
this.arr = [1,2,3]
}
Parent.prototype.say = function () {
console.log('say hello');
}
function Child() {
Parent.call(this) //继承parent构造函数里面的方法
this.type = 'child'
}
Child.prototype = Object.create(Parent.prototype)//为什么要有这一步呢,如果直接执行下面那一步,那么因为Child和Parent的原型是一样的,所以如果直接改了Child原型上的prototype的构造器属性会导致Parent上的构造器属性也一样指向了Child构造函数,这样就失去意义了,所以要根据Object.create来当一个中间对象,隔绝这层联系
Child.prototype.constructor = Child;//修正一下构造器属性
ES6方式实现继承
class Parent{
constructor(name){
this.name = name
}
getName(){
console.log(this.name);
}
}
class Child extends Parent{
//es6中主要通过extends去继承原型链上面的,super去继承实例上的
constructor(name,age){
super(name);
this.age = age
}
getAge(){
console.log(this.age);
}
}
const child = new Child('jj',18);
child.getName(); //jj
child.getAge(); //18
这里的constructor里面的super大概等于之前的 Parent.call(this)
这里就是面向对象继承的内容了
网友评论