为了账号安全,请及时绑定邮箱和手机立即绑定

JavaScript 中的继承

标签:
JavaScript

摘要:继承是面向对象思想中的重要概念,虽然严格来说 JavaScript 并属于面向对象类型的语言,但最终还是在ES 6 中正式引入了继承的概念。本文就来介绍一下继承的概念、以及在 ES5 和 ES6 中两种写继承的方法。

面向对象中的继承

话不多说,先来看一下维基百科的解释

继承( inheritance)是面向对象软件技术当中的一个概念。如果一个类别B“继承自”另一个类别A,就把这个B称为“A的子类”,而把A称为“B的父类别”也可以称“A是B的超类”。继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码。

所以我们知道了继承是类和类之间的关系,它使得子类具有了父类别的各种属性和方法。所以继承这个概念本身是属于面向对象编程的,只有面向对象编程里面才有类的概念。
然而 JavaScript 是函数式编程,根本就没有类的概念,那么 JS 中的继承的概念从何谈起呢?

JavaScript 中的继承

在说 JS 的继承之前,我们得先了解原型链的概念,简单来说就是每一个对象都有一个__proto__ 属性,指向该对象的原型 prototype,原型的层层指向就形成了一个类似链表的结构(实际上原型的指向是多对一的,所以把这种结构说成“树”更准确一点)称之为原型链。

JavaScript 对象是动态的属性“包”(指其自己的属性)。JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

而 JavaScript 中的继承就是基于原型链的继承
由于JS里面没有类,只有函数,所以我们只好这么称呼:子类函数、父类函数(比如 ArrayObject 的关系),因此可以这么解释继承:子类函数构造出来的对象直接拥有父类的属性。

因此,我们要写出继承,还得先写一个类,那么类到底是什么呢:能产生对象的东西即为类,那么,下面的代码中,Human 就可以称之为类。person 就是一个有自己属性的对象。

function Human(name){   this.name = name
}var person = new Human('Enoch')

如果我们想在它的原型链上加一个属性,就可以这么写:

Human.prototype.run = function(){}

现在 person 的原型结构就是这样的:

webp


有了类,下面就可以来写继承了,我们要实现一个类 Man 继承自 Human,他有自己的属性,同时也继承了 Human 的属性和方法。

ES 5 中的继承写法

 function Human(name){     // 自身的属性 
     this.name = name
 }// 原型链第一层的属性
 Human.prototype.run = function(){     console.log("我叫"+this.name+",我在跑")     return undefined
 }// 声明一个 Man 类
 function Man(name){     // 使得 Man 类有了 Human 类 第一层的 name 属性
     // 即实现了对象本身属性的添加 
     Human.call(this, name)     this.gender = '男'
 } // 接下来要实现 Man 也拥有 Human 第二层的方法 run
 // 最简单的方式是:
 // Man.prototype.__proto__ = Human.prototype
 // 但是上一句不符合 ECMA 标准,因此要写下面三行
 var f = function(){}
 f.prototype = Human.prototype
 Man.prototype = new f() // 此为 Man 类自身具有的方法,处于原型链第二层
 Man.prototype.fight = function(){     console.log('糊你熊脸')
 }

写好以后,声明一个 person 对象: var person = new Man('Enoch')
此时  person 的结构如下:

webp


我们来理一下 person 对象的原型链

person.__proto__ === Man.prototype
person.__proto__.__proto__ === Human.prototype
person.__proto__.__proto__.__proto__ === Object.prototype
person.__proto__.__proto__.__proto__.__proto__ === null

ES 6 中的继承写法

需要注意的是,ES 6 虽然新增了 class 语法,但它本质上只是一个语法糖而已,JavaScript 目前为止仍然是基于原型链的继承,没有真正的类的概念。

 class Human{     constructor(name){         this.name = name
     }
     run(){         console.log("我叫"+this.name+",我在跑")         return undefined
     }
 } // extends 关键字 等价于 
 // Man.prototype.__proto__ = Human.prototype
 class Man extends Human{     constructor(name){         // super(name) 等价于 Human.call(this,name)
         super(name)         this.gender = '男'
     }
     fight(){         console.log('糊你熊脸')
     }
 }

ES 6 写法的不足

看了上一节,我们会发现 ES 6 写起来好爽,代码简洁了很多,而且曾经写过 Java 的同学还会觉得分外亲切,因为这种写法就是 JavaScript 借( chao )鉴( xi )了 Java 的类的继承的操作。但是这么写还有一个需求不太容易实现。
比如我们需要在类的原型上写一个不是函数的属性,比如 Human 的原型上有一个 种族 race 的属性, 就不能直接写,如要如下操作:

class Human {  constructor(name){    this.name = name
  }
  get race(){    return '人类'
  }
  run(){}
}

然后一个person = new Human('Enoch') 就呈现了如下结构

webp

而我们如果用 ES 5 的写法就很容易:

function Human(name){   this.name = name
}
Human.prototype.race = '人类'

person 的结构如下:

webp



作者:EnochQin
链接:https://www.jianshu.com/p/f0e1dd1b90b0


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消