关于原型链的知识,我刚开始就是看一篇一篇的博客,知识有点零碎,后面看了下《JS高级程序设计》,又大体整合了一下。下面记录的是,对于一条完整的原型链长什么样这个问题的思考。javascript
借用一段在《JS高级程序设计》中的一段代码:html
function Person(){} Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); //"Nicholas" var person2 = new Person(); person2.sayName(); //"Nicholas" alert(person1.sayName == person2.sayName); //true
此段代码中,构造函数Person
,原型对象Person.prototype
以及实例对象person1
和person2
的关系以下图所示:java
按照书上的解释,很好理解,但很显然,它并非一条完整的原型链,而且我也有疑问:书中给出的示例图中没有画构造函数Person和原型对象Person.prototype的_proto_属性。segmentfault
首先:_proto_
属性是个对象都有,那么,在万物皆对象的JS中,构造函数Person
和原型对象Person.prototype
的_proto_
属性又指向哪里呢??其次,就这个问题,结合上面给出的代码,能够将一条完整的原型链用相似上面的图画出来吗??函数
以前看了一篇博文,其中分析了_proto_
应该指向谁的问题,举了下面这个例子,可能直接看会有点蒙圈,原文: JS原型链简单图解 - 最骚的就是你 - 博客园工具
对应的示例代码以下:this
var A = function(){}; var a = new A(); console.log(a.__proto__); //A {}(A.prototype即A的原型对象) console.log(a.__proto__.__proto__); //Object {}(Object.prototype即Object的原型对象) console.log(a.__proto__.__proto__.__proto__); //null
其实,对于a._proto_ ==A.prototype
以及Object.prototype._proto_==null
比较好理解:.net
使用函数表达式方法建立的函数变量A,就是新的函数变量a的构造函数,因此a的原型对象就是其构造函数的prototype所指的对象:A.prototype
而Object.prototype._proto_为何是null能够参考:为何原型链的终点是null,而不是Object.prototype?- 余百炼的博客 - CSDN博客prototype
然而,为何A.prototype
的原型是Object.prototype
,即A.prototype._proto_==Object.prototype
怎么解释呢??设计
其实,原型链是指对象的原型链,这个链上的节点都是一级一级的原型对象,因此原型链上的全部节点都是对象!!!所以这就好理解了,A.prototype
是一个对象,而后它是Object
的一个实例,因此它的原型是Object.prototype
。
这里须要注意的是,a虽然是原型链上的起点,它也是对象,可是它的原型并非直接就是Object.prototype,它的原型是其构造函数的prototype所指的对象:A.prototype
其实这个图描述的还只是局部 ,不利于理解,请看下面的图:(图片取自javascript - 为何原型链的终点是null,而不是Object.prototype - SegmentFault 思否 )
从这张大图中咱们能够看出来,
fun._proto_
)都是Function.prototype
,不管是JS原生的构造函数如Function仍是Object等仍是用户自定义的构造函数如上图的Foo;fun.prototype._proto_
)都是Object.prototype
,不管是自定义的仍是原生的(Object除外);根据这个图,能够更好的理解下面这两句话:
_proto_
是任何对象都有的属性,而JS里万物都是对象,因此会造成一条_proto_
连起来的链条,递归访问_proto_
必须最终到头,而且值是null;prototype
这样的话,关系就比较明了了。因此,文章开头的那段代码的原型链应该以下图所示:
function Person(){} Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); //"Nicholas" var person2 = new Person(); person2.sayName(); //"Nicholas" alert(person1.sayName == person2.sayName); //true
趁着这个机会,能够讨论一下原生构造函数Object
和Function
到底什么关系?
从上图中咱们能够把Function
和Object
部分单独摘出来:
Function._proto_==Function.prototype==function(){} Function._proto_._proto_==Object.prototype Function._proto_._proto_._proto_==Object.prototype._proto_==null Object._proto_ === Function.prototype==function(){} Object._proto_._proto_==Object.prototype Object._proto_._proto_._proto_==null
从上图中能够看到构造函数之间的关系以下:
Object.prototype.constructor===Object Object instanceof Function;//true Object.constructor===Function Function.prototype.constructor===Function Function instanceof Object;//true Function.constructor===Function