继承是面向对象编程中又一非常重要的概念,JavaScript支持实现继承,不支持接口继承,实现继承主要依靠原型链来实现的。
原型链
首先得要明白什么是原型链,在一篇文章看懂proto和prototype的关系及区别中讲得非常详细
原型链继承基本思想就是让一个原型对象指向另一个类型的实例
function SuperType() {
this.property = true
}
SuperType.prototype.getSuperValue = function () {
return this.property
}
function SubType() {
this.subproperty = false
}
SubType.prototype = new SuperType()
SubType.prototype.getSubValue = function () {
return this.subproperty
}
var instance = new SubType()
console.log(instance.getSuperValue()) // true
代码定义了两个类型SuperType和SubType,每个类型分别有一个属性和一个方法,SubType继承了SuperType,而继承是通过创建SuperType的实例,并将该实例赋给SubType.prototype实现的。
实现的本质是重写原型对象,代之以一个新类型的实例,那么存在SuperType的实例中的所有属性和方法,现在也存在于SubType.prototype中了。
我们知道,在创建一个实例的时候,实例对象中会有一个内部指针指向创建它的原型,进行关联起来,在这里代码SubType.prototype = new SuperType(),也会在SubType.prototype创建一个内部指针,将SubType.prototype与SuperType关联起来。
所以instance指向SubType的原型,SubType的原型又指向SuperType的原型,继而在instance在调用getSuperValue()方法的时候,会顺着这条链一直往上找。
添加方法
在给SubType原型添加方法的时候,如果,父类上也有同样的名字,SubType将会覆盖这个方法,达到重新的目的。 但是这个方法依然存在于父类中。
记住不能以字面量的形式添加,因为,上面说过通过实例继承本质上就是重写,再使用字面量形式,又是一次重写了,但这次重写没有跟父类有任何关联,所以就会导致原型链截断。
function SuperType() {
this.property = true
}
SuperType.prototype.getSuperValue = function () {
return this.property
}
function SubType() {
this.subproperty = false
}
SubType.prototype = new SuperType()
SubType.prototype = {
getSubValue:function () {
return this.subproperty
}
}
var instance = new SubType()
console.log(instance.getSuperValue()) // error
问题
单纯的使用原型链继承,主要问题来自包含引用类型值的原型。
function SuperType() {
this.colors = ['red', 'blue', 'green']
}
function SubType() {
}
SubType.prototype = new SuperType()
var instance1 = new SubType()
var instance2 = new SubType()
instance1.colors.push('black')
console.log(instance1.colors) // ["red", "blue", "green", "black"]
console.log(instance2.colors) // ["red", "blue", "green", "black"]
在SuperType构造函数定义了一个colors属性,当SubType通过原型链继承后,这个属性就会出现SubType.prototype中,就跟专门创建了SubType.prototype.colors一样,所以会导致SubType的所有实例都会共享这个属性,所以instance1修改colors这个引用类型值,也会反映到instance2中。
借用构造函数
此方法为了解决原型中包含引用类型值所带来的问题。
这种方法的思想就是在子类构造函数的内部调用父类构造函数,可以借助apply()和call()方法来改变对象的执行上下文
function SuperType() {
this.colors = ['red', 'blue', 'green']
}
function SubType() {
// 继承SuperType
SuperType.call(this)
}
var instance1 = new SubType()
var instance2 = new SubType()
instance1.colors.push('black')
console.log(instance1.colors) // ["red", "blue", "green", "black"]
console.log(instance2.colors) // ["red", "blue", "green"]
在新建SubType实例是调用了SuperType构造函数,这样以来,就会在新SubType对象上执行SuperType函数中定义的所有对象初始化代码。
结果,SubType的每个实例就会具有自己的colors属性的副本了。
传递参数
借助构造函数还有一个优势就是可以传递参数
function SuperType(name) {
this.name = name
}
function SubType() {
// 继承SuperType
SuperType.call(this, 'Jiang')
this.job = 'student'
}
var instance = new SubType()
console.log(instance.name) // Jiang
console.log(instance.job) // student
问题
如果仅仅借助构造函数,方法都在构造函数中定义,因此函数无法达到复用
组合继承(原型链+构造函数)
组合继承是将原型链继承和构造函数结合起来,从而发挥二者之长的一种模式。
思路就是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
function SuperType(name) {
this.name = name
this.colors = ['red', 'blue', 'green']
}
SuperType.prototype.sayName = function () {
console.log(this.name)
}
function SubType(name, job) {
// 继承属性
SuperType.call(this, name)
this.job = job
}
// 继承方法
SubType.prototype = new SuperType()
SubType.prototype.constructor = SuperType
SubType.prototype.sayJob = function() {
console.log(this.job)
}
var instance1 = new SubType('Jiang', 'student')
instance1.colors.push('black')
console.log(instance1.colors) //["red", "blue", "green", "black"]
instance1.sayName() // 'Jiang'
instance1.sayJob() // 'student'
var instance2 = new SubType('J', 'doctor')
console.log(instance2.colors) // //["red", "blue", "green"]
instance2.sayName() // 'J'
instance2.sayJob() // 'doctor'
这种模式避免了原型链和构造函数继承的缺陷,融合了他们的优点,是最常用的一种继承模式。
原型式继承
借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
function object(o) {
function F() {}
F.prototype = o
return new F()
}
在object函数内部,先创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。
本质上来说,object对传入其中的对象执行了一次浅复制。
var person = {
name: 'Jiang',
friends: ['Shelby', 'Court']
}
var anotherPerson = object(person)
console.log(anotherPerson.friends) // ['Shelby', 'Court']
这种模式要去你必须有一个对象作为另一个对象的基础。
在这个例子中,person作为另一个对象的基础,把person传入object中,该函数就会返回一个新的对象。
这个新对象将person作为原型,所以它的原型中就包含一个基本类型和一个引用类型。
所以意味着如果还有另外一个对象关联了person,anotherPerson修改数组friends的时候,也会体现在这个对象中。
Object.create()方法
ES5通过Object.create()方法规范了原型式继承,可以接受两个参数,一个是用作新对象原型的对象和一个可选的为新对象定义额外属性的对象,行为相同,基本用法和上面的object一样,除了object不能接受第二个参数以外。
var person = {
name: 'Jiang',
friends: ['Shelby', 'Court']
}
var anotherPerson = Object.create(person)
console.log(anotherPerson.friends) // ['Shelby', 'Court']
寄生式继承
寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数。
function createAnother(o) {
var clone = Object.create(o) // 创建一个新对象
clone.sayHi = function() { // 添加方法
console.log('hi')
}
return clone // 返回这个对象
}
var person = {
name: 'Jiang'
}
var anotherPeson = createAnother(person)
anotherPeson.sayHi()
基于person返回了一个新对象anotherPeson,新对象不仅拥有了person的属性和方法,还有自己的sayHi方法。
在主要考虑对象而不是自定义类型和构造函数的情况下,这是一个有用的模式。
寄生组合式继承
在前面说的组合模式(原型链+构造函数)中,继承的时候需要调用两次父类构造函数。
父类
function SuperType(name) {
this.name = name
this.colors = ['red', 'blue', 'green']
}
第一次在子类构造函数中
function SubType(name, job) {
// 继承属性
SuperType.call(this, name)
this.job = job
}
第二次将子类的原型指向父类的实例
// 继承方法 SubType.prototype = new SuperType()
当使用var instance = new SubType()的时候,会产生两组name和color属性,一组在SubType实例上,一组在SubType原型上,只不过实例上的屏蔽了原型上的。
使用寄生式组合模式,可以规避这个问题。
这种模式通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
基本思路:不必为了指定子类型的原型而调用父类的构造函数,我们需要的无非就是父类原型的一个副本。
本质上就是使用寄生式继承来继承父类的原型,在将结果指定给子类型的原型。
function inheritPrototype(subType, superType) {
var prototype = Object.create(superType.prototype)
prototype.constructor = subType
subType.prototype = prototype
}
该函数实现了寄生组合继承的最简单形式。
这个函数接受两个参数,一个子类,一个父类。
第一步创建父类原型的副本,第二步将创建的副本添加constructor属性,第三部将子类的原型指向这个副本。
function SuperType(name) {
this.name = name
this.colors = ['red', 'blue', 'green']
}
SuperType.prototype.sayName = function () {
console.log(this.name)
}
function SubType(name, job) {
// 继承属性
SuperType.call(this, name)
this.job = job
}
// 继承
inheritPrototype(SubType, SuperType)
var instance = new SubType('Jiang', 'student')
instance.sayName()
补充:直接使用Object.create来实现,其实就是将上面封装的函数拆开,这样演示可以更容易理解。
function SuperType(name) {
this.name = name
this.colors = ['red', 'blue', 'green']
}
SuperType.prototype.sayName = function () {
console.log(this.name)
}
function SubType(name, job) {
// 继承属性
SuperType.call(this, name)
this.job = job
}
// 继承
SubType.prototype = Object.create(SuperType.prototype)
// 修复constructor
SubType.prototype.constructor = SubType
var instance = new SubType('Jiang', 'student')
instance.sayName()
ES6新增了一个方法,Object.setPrototypeOf,可以直接创建关联,而且不用手动添加constructor属性。
// 继承 Object.setPrototypeOf(SubType.prototype, SuperType.prototype) console.log(SubType.prototype.constructor === SubType) // true
以上所述是小编给大家介绍的JavaScript的六种继承方式(推荐),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
# js
# 继承方式
# js中常见的6种继承方式总结
# js继承的6种方式详解
# JavaScript 常见的继承方式汇总
# js继承的这6种方式!(上)
# JavaScript实现继承的6种常用方式总结
# 子类
# 就会
# 自己的
# 创建一个
# 重写
# 来实现
# 本质上
# 也会
# 在这个
# 有一个
# 会在
# 自定义
# 小编
# 复用
# 有任何
# 实现了
# 他们的
# 都有
# 在这里
# 也有
相关文章:
在线教育网站制作平台,山西立德教育官网?
建站主机类型有哪些?如何正确选型
如何在万网开始建站?分步指南解析
XML的“混合内容”是什么 怎么用DTD或XSD定义
c++如何打印函数堆栈信息_c++ backtrace函数与符号名解析【方法】
网站建设设计制作营销公司南阳,如何策划设计和建设网站?
为什么Go需要go mod文件_Go go mod文件作用说明
已有域名如何免费搭建网站?
湖州网站制作公司有哪些,浙江中蓝新能源公司官网?
网站制作大概要多少钱一个,做一个平台网站大概多少钱?
详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)
制作网站的过程怎么写,用凡科建站如何制作自己的网站?
免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?
如何通过VPS搭建网站快速盈利?
惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?
免费视频制作网站,更新又快又好的免费电影网站?
建站之星代理商如何保障技术支持与售后服务?
制作网站的模板软件,网站怎么建设?
如何用免费手机建站系统零基础打造专业网站?
企业网站制作公司网页,推荐几家专业的天津网站制作公司?
如何在宝塔面板中创建新站点?
如何选择长沙网站建站模板?H5响应式与品牌定制哪个更优?
h5在线制作网站电脑版下载,h5网页制作软件?
怎么用手机制作网站链接,dw怎么把手机适应页面变成网页?
太平洋网站制作公司,网络用语太平洋是什么意思?
PHP 500报错的快速解决方法
免费制作小说封面的网站有哪些,怎么接网站批量的封面单?
定制建站平台哪家好?企业官网搭建与快速建站方案推荐
网站制作软件有哪些,制图软件有哪些?
如何快速生成高效建站系统源代码?
如何撰写建站申请书?关键要点有哪些?
Swift开发中switch语句值绑定模式
小程序网站制作需要准备什么资料,如何制作小程序?
可靠的网站设计制作软件,做网站设计需要什么样的电脑配置?
如何通过云梦建站系统实现SEO快速优化?
如何在阿里云香港服务器快速搭建网站?
青浦网站制作公司有哪些,苹果官网发货地是哪里?
建站之星如何快速生成多端适配网站?
php条件判断怎么写_ifelse和switchcase的使用区别【对比】
如何设计高效校园网站?
佛山企业网站制作公司有哪些,沟通100网上服务官网?
网站制作知乎推荐,想做自己的网站用什么工具比较好?
如何通过商城免费建站系统源码自定义网站主题?
微信推文制作网站有哪些,怎么做微信推文,急?
专业的网站制作设计是什么,如何制作一个企业网站,建设网站的基本步骤有哪些?
MySQL查询结果复制到新表的方法(更新、插入)
网页设计与网站制作内容,怎样注册网站?
建站主机选虚拟主机还是云服务器更好?
深圳网站制作费用多少钱,读秀,深圳文献港这样的网站很多只提供网上试读,但有些人只要提供试读的文章就能全篇下载,这个是怎么弄的?
香港服务器租用每月最低只需15元?
*请认真填写需求信息,我们会在24小时内与您取得联系。