这篇文章的重点讲的是关于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
复制代码
以上代码中,f1
是Foo
函数经过new
构造出来的对象,f1.a
是f1
对象的基本属性,而f1.b
是从Foo.prototype
继承获得的,由于f1.__proto__
指向的是Foo.prototype
。编程语言
这里有一个重要的规则:当访问一个对象的属性时,首先在基本属性中查找,若是没有,再沿着__proto__
这条链往上找,看是否在链上,有的话就能继承这一属性,若是没有,就返回undefined
,这就是原型链,又复习一遍咯。函数
看图直观一些,这里仍是采用反复用的原型/原型链经典图:ui
上图中,访问f1.a
时,f1
的基本属性中有a
,则不会继续沿着__proto__
找,直接读出基本属性a
的值;而访问f1.b
时,f1
的基本属性中没有b
,因而沿着__proto__
找到了Foo.prototype.b
。spa
那咱们如何在实际应用中区分一个属性究竟是基本属性仍是在原型链中的公有属性呢?这里能够好好利用一下这个属性——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
中的方法,好比toString
、valueOf
等这些公有属性,这就是所谓的“继承”。
固然这只是一个例子,你能够自定义函数和对象来实现本身的继承,这一点后续文章会有专门介绍。
这里再说一个函数的例子来加深理解吧。
咱们都知道每一个函数都有apply
,call
方法,都有length
,arguments
,caller
等属性。为何每一个函数都有?这确定是“继承”来的。在介绍instanceof
这篇文章中也提到,函数是由Function
函数建立,都继承自Function.prototype
中的方法。不信能够在Chrome中打印出:
直接能够看到了吧,有call
、length
等这些属性。
那怎么还有hasOwnProperty
呢?上图中hasOwnProperty
右边显示Object
,表明Function.prototype
继承自Object.prototype
。有疑问能够再看看这张原型/原型链经典大图,Function.prototype.__proto__
会指向Object.prototype
。
最后仍是那句话,当你彻底搞懂上面这张图的时候,就是你掌握原型、原型链的时候了。
若是以为文章对你有些许帮助,欢迎在个人GitHub博客点赞和关注,感激涕零!