说到原型链,必须先抛出这张图了?
首先来梳理下这张图的信息:
-
图中有三个函数和四个实例对象:
三个函数:function Foo(){}、Object、Function
四个实例对象:f1、f2、o1、o2 -
函数Foo是通过new Function方式创建的,因此Foo的__proto__属性指向Function.prototype,即
Foo.__proto__===Function.prototype
-
函数Foo有一个prototype属性:Foo.prototype,该属性有一个constructor属性,指向函数Foo本身,即
Foo.prototype.constructor===Foo
,Foo.prototype还有一个__proto__属性,指向Object的prototype,即Foo.prototype.__proto__===Object.prototype
-
函数Foo的实例对象f1和f2有一个__proto__属性,指向函数Foo的prototype属性,即
f1.__proto__===Foo.prototype
,f2.__prototype===Foo.prototype
-
Object是通过new Function方式创建的,因此Object的__proto__属性指向Function.prototype,即
Object.__proto__===Function.prototype
-
Object有一个prototype属性:Object.prototype,该属性有一个constructor属性,指向Object本身,即
Object.prototype.constructor===Object
,Object.prototype也有个__proto__属性,指向null,即Object.prototype.__proto__===null
-
Object的实例对象o1和o2有一个__proto__属性,指向Object的prototype属性,即
o1.__proto__===Object.prototype
,o2.__proto__===Object.prototype
-
Function是通过new Function方式创建的,因此Function的__proto__属性指向Function.prototype,即
Function.__proto__===Function.prototype
-
Function有一个prototype属性:Function.prototype,该属性有一个constructor属性,指向Function本身,即
Function.prototype.constructor===Function
;Function.prototype也有一个__proto__属性,指向Object.prototype,即Function.prototype.__proto__===Object.prototype
总结一下重点:
- 函数有两个属性:__proto__和prototype
Object.__proto__===Function.prototype
Function.__proto===Function.prototype
Object.prototype.__proto__===null
原型链的基本思想是:利用原型让一个引用类型继承另一个引用类型的属性和方法。JavaScript高级程序设计中有关于构造函数、原型和实例关系的描述:
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。这就是所谓原型链的基本概念。
JavaScript中,一切引用类型和null皆对象。每个实例对象(object )都有一个私有属性(称之为__proto__)指向它的原型对象(prototype)。该原型对象也有一个自己的原型对象(__proto__
) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。但是对象也分普通对象和函数对象。普通对象的__proto__指向Object的prototype,而函数对象的__proto__指向Function的prototype。
javaScript的内置对象Array、Boolean、String、Number、Date、RegExp、Function、Object、Promise等都是函数对象,而JSON、Math等不是函数对象。即:
Array.__proto__===Function.prototype
Boolean.__proto__===Function.prototype
String.__proto__===Function.prototype
Number.__proto__===Function.prototype
Date.__proto__===Function.prototype
RegExp.__proto__===Function.prototype
Function.__proto__===Function.prototype
Object.__proto__===Function.prototype
Promise.__proto__===Function.prototype
JSON.__proto__===Object.prototype
Math.__proto__===Object.prototype
所以关于__proto__和prototype只要记下以下几点即可:
- __proto__是所有对象都有的,它是对象的原型,原型链就是靠它形成的。查看对象的__proto__来得知自己是基于什么prototype被制造的。而prototype只有函数(准确地说是构造函数)才有的,它也是一个对象(普通对象),它的作用是:构造函数new对象的时候,告诉构造函数新创建的对象的原型是谁。
- 普通对象的__proto__指向Object的prototype,函数对象的__proto__指向Function的prototype。
Object.prototype.__proto__===null
- 当访问一个实例属性时,首先会在该实例中搜索该属性,如果没有找到,则会继续搜索实例的原型,如果还是没有找到,则会在实例的原型的原型上找,搜索过程会沿着原型链向上查找,直到找到或找到Object.prototype为至。
- A instanceof B即判断
A.__proto__===B.prototype
的返回值
来几个例子理解下吧:
function F(){};
var o = {};
typeof F; //==> function
typeof o; //==> object
typeof F.prototype; //==> object,函数的prototype是一个对象,所以返回object
typeof o.prototype; //==> undefinded,只有函数才有prototype,o是一个对象,没有该属性
typeof new F; //==> object,通过new实例化了一个对象
typeof (new F).prototype; //==> undefined,对象是没有prototype属性的
typeof (new F).__proto__; //==> object,实例化出来的是一个普通对象,它的__proto__指向Object
typeof F.__proto__; //==> function
typeof o.__proto__; //==> object
typeof Object; //==> function
typeof Function; //==> function
typeof (new Function).prototype; //==> object
typeof (new Function).__proto__; //==> function
typeof (new Object).prototype; //==> undefined
typeof (new Object).__proto__; //==> object
typeof Object.prototype; //==> object
typeof Object.__proto__; //==> function
typeof Function.prototype; //==> function
typeof Function.__proto__; //==> function