原来JS可以这么实现继承

当我们在编写代码的时候,有一些对象内部会有一些方法(函数),如果将这些函数在构造函数内部声明会导致内存的浪费,因为实例化构造函数得到不同的实例对象,其内部都有同一个方法,但是占据了不同的内存,就存在内存浪费问题。于是乎我们就需要用到继承。

什么是继承?

通过某种方式让一个对象可以访问到另一个对象中属性和方法,我们将这种方法称之为继承(inheritance)

如果一个类B继承自另一个类A,就把B称之为A的子类,A称之为B的父类或者超类

如何实现继承?

1、原型链继承

// 原型链的继承
SuperType.prototype.getSuperValue = function () {return this.property;
}
function SuperType() {this.property = true
}

Type.prototype = new SuperType();

function Type() {this.typeproperty = false
}

console.log(Type.prototype);

var instance = new Type()

console.log(instance.getSuperValue());// true 

让SuperType的实例对象赋给Type的原型,Type就能继承到SuperType的属性和方法

优点:原型链继承容易上手,书写简单,父类可以复用,被多个子类继承。

缺点:会在子类实例对象上共享父类所有的引用类型实例属性,(子类改不动父类的原始类型),更改一个子类的引用属性,其他子类均受影响;子类不能改父类传参。

2、经典继承(伪造对象)

// 经典继承
SuperType.prototype.name = '寒月十九'

function SuperType(age) {this.color = ['red', 'green', 'blue'],this.age = age
}

function Type(age) {SuperType.call(this,age)
}

var instance = new Type(18)
console.log(instance);
console.log(instance.color); 

经典继承就是借助this的显示绑定,将SuperType的指向绑定到Type身上,使得我们可以直接访问到SuperType身上的属性。

优点:解决了原型链继承子类不能向父类传参的问题和原型共享的问题。

缺点:方法不能复用;子类继承不到父类原型上的属性,只能继承到父类实例对象上的属性。

3、组合继承(原型链继承 + 经典继承)

// 组合继承 (伪经典继承)
SuperType.prototype.sayName =function() {console.log(this.name);
}

function SuperType(name) {this.name = name,this.color = ['red', 'green', 'blue']
}
function Type(age,name) {this.age = ageSuperType.call(this,name)
}

Type.prototype = new SuperType()
Type.prototype.constructor = Type//Type.prototype被替换了,所以要补充一个constructor属性,指向自身,这样new Type得到的实例对象就有constructor属性

Type.prototype.sayAge = function() {console.log(this.age)
}

var instance = new Type(20,'寒月十九');
instance.sayAge(); 

组合继承就是将上面两种继承方式结合起来,先将SuperType的this指向显示绑定到Type,然后再替换Type的原型,再添加上构造器属性指向自身,使得new Type()得到的实例对象就具备构造属性,并且可以继承到SuperType的属性。

优点:解决了原型链继承和经典继承的缺点造成的影响。

缺点:每一次都会调用两次父类的构造函数,一次是在创建子类原型上,另一次是在子类构造函数内部。

4、原型式继承

(1)借助构造函数实现对象的继承

// 原型式继承
function object(obj) {function newFn() {}newFn.prototype = obj;return new newFn();
};
var person = {name: '寒月十九',age: 20,like: {sport: 'coding'}
};
let newObj = object(person); 

(2)Object.create()

var person = {name: '寒月十九',age: 20,like: {sport: 'coding'}
};
let newPerson = Object.create(person,{sex: 'boy'}); 

优点:不需要单独构建构造函数。

缺点:属性中的引用地址会在相关对象中共享。

5、寄生式继承

function createPerson(original) {var clone = Object.create(original)clone.say = function() {// 增强这个对像console.log('hello');}return clone;
};
var person = {name: '寒月十九',age: 20,like: {sport: 'coding'}
};
let newPerson =createPerson(person); 

寄生式继承是原型式继承的加强版,它结合原型式继承和工厂模式,创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回对象。

优点:上手简单,不用单独创建构造函数。

缺点:寄生式继承给对象添加函数会导致函数难以重用,因此不能做到函数复用而效率降低;引用类型的属性始终都会被继承所共享。

寄生组合式继承

// 寄生组合式继承
SuperType.prototype.sayName = function() {console.log(this.name);
};
SuperType.prototype.like = {a: 1,b: 2
};
function SuperType(name) {this.name = name;this.colors = ['red', 'blue', 'green']
};

function Type(name, age) {this.age = age;SuperType.call(this, name);
}

var anotherPrototype = Object.assign(Type.prototype, SuperType.prototype);
// anotherPrototype.constructor = Type

Type.prototype = anotherPrototype; // new SuperType() 

寄生组合继承是为降低父类构造函数的开销。通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

优点:高效,只调用一个次父构造函数,不会在原型上添加多余的属性,原型链还能保持不变;开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。

缺点:代码较复杂。

class类继承

class Parent{constructor(name) {this.name = name;this.hobbies = ["running", "basketball", "writting"];}getHobbies() {return this.hobbies;}static getCurrent() {// 静态方法,只能类本身调用console.log(this);}
}

class Child extends Parent {constructor(name) {super(name);}
}

var c1 = new Child('寒月十九');
var c2 = new Child('十九'); 

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值