JavaScript系列之对象的继承

这篇文章的重点讲的是关于JavaScript中对象的继承,这是面向对象编程很重要的一个方面。A 对象继承自B 对象,就能直接拥有 B 对象的全部属性和方法,做用是避免了代码的复用,节省代码量。javascript

而大部分面向对象的编程语言,都是经过“类”(class)来实现对象的继承。传统上,JavaScript 语言的继承不经过 class(ES6 引入了 class 语法,基于 class 的继承不在这里介绍),而是经过“原型对象”(prototype)实现,所以,这里把“继承”着重拿出来说,就为了体现这个不一样。java

复习原型/原型链

JavaScript的继承得靠原型/原型链来实现,固然原型/原型链不是这篇文章的重点,以前的文章也已经介绍过了,因此这里咱们来复习一下便可。git

其实原型的概念很简单,我以为用如下简短的几句话就能归纳彻底了:github

  • 全部对象都有一个属性 __proto__ 指向一个对象,也就是原型
  • 每一个对象的原型均可以经过 constructor 找到构造函数,构造函数也能够经过 prototype 找到原型
  • 全部函数均可以经过 __proto__ 找到 Function 对象
  • 全部对象均可以经过 __proto__ 找到 Object 对象
  • 对象之间经过 __proto__ 链接起来,这样称之为原型链。当前对象上不存在的属性能够经过原型链一层层往上查找,直到顶层 Object 对象,顶层 Object 对象最终指向null

我以为原型中最重要的内容其实就这些了,不必看太多关于原型的文章,到头来只是会愈来愈糊涂,若是硬要推荐原型参阅资料的话,《JavaScript高级程序设计》这本书,当之无愧!编程

继承

经过上面的介绍,咱们知道JavaScript中的继承是经过原型/原型链来体现的,先看几行代码:app

function Foo() { }
var f1 = new Foo();

f1.a = 10;

Foo.prototype.a = 100;
Foo.prototype.b = 200;

console.log(f1.a);  // 10
console.log(f1.b);  // 200
console.log(f1.c);  // undefined
复制代码

以上代码中,f1Foo函数经过new构造出来的对象,f1.af1对象的基本属性,而f1.b是从Foo.prototype继承获得的,由于f1.__proto__指向的是Foo.prototype编程语言

这里有一个重要的规则:当访问一个对象的属性时,首先在基本属性中查找,若是没有,再沿着__proto__这条链往上找,看是否在链上,有的话就能继承这一属性,若是没有,就返回undefined,这就是原型链,又复习一遍咯。函数

看图直观一些,这里仍是采用反复用的原型/原型链经典图:ui

上图中,访问f1.a时,f1的基本属性中有a,则不会继续沿着__proto__找,直接读出基本属性a的值;而访问f1.b时,f1的基本属性中没有b,因而沿着__proto__找到了Foo.prototype.bspa

那咱们如何在实际应用中区分一个属性究竟是基本属性仍是在原型链中的公有属性呢?这里能够好好利用一下这个属性——hasOwnProperty,一下就能测出谁是基本属性,当在for…in…循环中,须要额外注意。

hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具备指定的属性,因此上图中,右边的只打印出a一个值,由于b是在Foo.prototype上的,不属于自身属性。

f1的这个hasOwnProperty()方法,f1自身没有,Foo.prototype中也没有,又是从何而来呢?

仍是引用那张原型/原型链经典图,从图上来看,hasOwnProperty()方法是从Object.prototype中继承来的:

因此对象的原型链是沿着__proto__这条线走的,所以在查找f1.hasOwnProperty属性时,由于自身没有这一属性,就会沿着原型链一直查找到Object.prototype上有这一属性,若是没找到则返回undefined

因为全部的对象的原型链都会最终找到Object.prototype,所以全部的对象都会有Object.prototype中的方法,好比toStringvalueOf等这些公有属性,这就是所谓的“继承”。

固然这只是一个例子,你能够自定义函数和对象来实现本身的继承,这一点后续文章会有专门介绍。

这里再说一个函数的例子来加深理解吧。

咱们都知道每一个函数都有applycall方法,都有lengthargumentscaller等属性。为何每一个函数都有?这确定是“继承”来的。在介绍instanceof这篇文章中也提到,函数是由Function函数建立,都继承自Function.prototype中的方法。不信能够在Chrome中打印出:

直接能够看到了吧,有calllength等这些属性。

那怎么还有hasOwnProperty呢?上图中hasOwnProperty右边显示Object,表明Function.prototype继承自Object.prototype。有疑问能够再看看这张原型/原型链经典大图,Function.prototype.__proto__会指向Object.prototype

最后仍是那句话,当你彻底搞懂上面这张图的时候,就是你掌握原型、原型链的时候了。

若是以为文章对你有些许帮助,欢迎在个人GitHub博客点赞和关注,感激涕零!

相关文章
相关标签/搜索