1、首先构造函数为中心
function Person() { }
var p = new Person();
console.log('Person::', p)
console.log(p.constructor === Person)
打印如下:
可以看出构造函数通过new得到实例,实例可以通过【constructor】得到构造函数。
访问原型的方式:
① 显示原型 构造函数通过prototype访问原型
② 隐私原型(向上) 实例通过__proto__访问原型
也就是 p.__proto === Person.prototype
根据上述画出他们的关系图如下:
2、以Object为中心
对象的一些创建方式:
var obj1 = {};
var obj2 = new Object();
这里我们用new的方式创建一个对象:
var obj = new Object();
打印对象实例的原型(obj.__proto__
);)如下图:
有上图可以看出实例obj的__proto__已经到顶,如果在__proto__去找,就找到了null,也就是obj.__proto__
.__proto__
=== null。
接下来我们在拿上边的Person举例
function Person(){};
var p1 = new Person();
console.log(p1.__proto__.__proto__.__proto__ === null ) // true
通过Person的实例去找原型,通过三次__proto__才找到null,p1为什么要比obj多一层呐?其实主要就是构造函数中存在 Person 比Object多一层prototype作为自定义属性原型使用。
下边在画一下已Object为中心的关系图如下:
将上边两个关系图连起来:
3、下边已Function为中心:
首先我们定义一个函数var fn = new Function();
然后打印这个fn,结果如下图:
有打印机结果,可以看出实例fn 也可以通过两次__proto__找到object原型,到这里有个疑问就是实例fn 一次__proto__是什么?
打印一下fn.__proto__结果如下(这里注意下Function.prototype也是这个结果,也就是fn.__proto__
===Function.prototype的结果是true ):
可以看出是[native code], 而native code 是底层的一个函数,其实负责函数的调用,底层代码我们是看不到的,在这里我么也可以看出函数也需要具备对象的能力。
和上边的已构造函数和Object为中心的关系连起来如下图:
这里再重点说下Function:
首先思考一个问题,__prroto__其实在任何的对象上都可以用,那么函数其实也是一个对象,那么Function.__proto__是什么呐?__proto__是用来找原型的,那么Function.__proto__就是再找函数的原型,我们打印Function.proto__可以看下,也是一个[native code],所以到这里我们可以知道Function. proto __ === Function.prototype的结果也是true,也就是他们都会找到底层的一个函数,这里我们可以得出一个结论:无论是Function.proto 找原型还是Function.prototype的方式找原型都是一样的结果,如下图:
总结:由于Function既是对象也是函数,所以自身和创建的实例,都指向function原型。
补充:基本类型的包装类型也是有原型的如下图: