上一篇讲了
①原型对象是什么;
②__proto__
、prototype
、constructor
的关系;
③原型对象的作用;
④原型对象带来的一些需要注意的问题;
没理解的可以再复习一下。
传送门:JS基础—原型对象的那些事(一)
今天讲一下原型链以及原型链的关系图。
原型链是什么
每个对象都有一个__proto__
属性,指向对象的原型。
ps:准确的说,是每一个实例都有一个[[Prototype]]
属性,指向原型对象。这是一个隐式属性,存在但是我们的脚本访问不到,不过浏览器厂商大部分都支持一个__proto__
属性,用来显示指向原型,虽然能用,但__proto__
不是ECMA中的规范。
原型的值可以是一个对象,也可以是null
。如果它的值是一个对象,那么这个对象也一定有自己的原型。这样就形成了一条线性的链,我们称之为原型链。
当我们在对象上调用一个属性或者方法时,会先在这个对象上寻找,没有的话就去它的原型对象上找,原型对象上没有就去原型对象的原型对象上找,一直找到原型对象为null
为止,没有的话就是undefined
。
简而言之,对象寻找一个属性会沿着原型链向上寻找,直到原型链的顶端。
还是以上一篇的Person
为例
function Person(name) {
this.name = name
}
Person.prototype.sayName = function() {
console.log(this.name)
}
var person = new Person("张三")
我们先来画一个简单的关于原型的关系图
以上是实例、构造函数和原型对象三者的关系图。
PS: prototype
只是构造函数上的一个属性,它是一个指针,指向原型对象,并不表示Person.prototype就是原型对象。这里将Person.prototype
认为是原型对象,是为了方便理解,需要注意哦。
看不懂的同学去复习上一篇的内容,看懂的我们继续。
注意点一
原型对象也是对象,是对象就有__proto__
属性,指向它的原型对象。
在上一个例子中,Person.prototype
就是一个对象,这个对象可以说是原生Object
构造函数的实例,所以
Person.prototype.__proto__ === Object.prototype
Object.prototype
也是一个对象,所以它也有__proto__
属性,不过它的__proto__
指向null
,也就是原型链的顶端,再往上就没有了。
重新补充一下关系图
看懂的我们继续
注意点二
任何函数都可以说是原生Function
构造函数的实例。
所以Person
构造函数是Function
构造函数的实例。
Person.__proto__ === Function.prototype
继续我完善我们的关系图
可能有人疑惑,Person
不是函数吗,函数怎么也有__proto__
,函数不是只有prototype
吗?
因为函数本质也是对象啊,在JS的世界里,万物皆对象,所以函数有__proto__
没毛病。
注意点三
Function.prototype
也是对象,所以和Person.prototype
一样,Function.prototype
可以说是原生Object
构造函数的实例,所以
Function.prototype.__proto__ === Object.prototype
补充我们的图(红色的线)
注意点四
Function
和Object
都是构造函数,根据第二点任何函数都可以说是原生Function
构造函数的实例,那么
Function.__proto__ === Function.prototype
Object.__proto__ === Function.prototype
完善我们的图(蓝色的线),大功告成。
恩,就是这么神奇,Function
是Function
的实例。。。
以上就是原型链的关系图,将这个图弄懂,原型对象的知识基本就掌握了。
虽然在真实场景中,这些知识用到的没这么复杂,但是掌握了最基础的知识,将来出现问题时,就能更快的找到问题的原因。
对于新手而言,原型链和作用域链经常搞混,this和静态作用域不知道在场景中怎么使用,确实是很头疼的问题,但这也许就是js的魅力所在吧。有时间的话再写一下作用域的知识~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。