JS每个对象都有一个内部属性[[prototype]],我们通常称之为原型.原型的值可以是一个对象,也可以是null.如果它的值是一个对象,则这个对象也一定有自己的原型.这样就形成了一条线性的链,我们称之为原型链。


访问一个对象的原型可以使用ES5中的Object.getPrototypeOf方法,或者ES6中的__proto__属性。


原型链的作用是用来实现继承,比如我们新建一个数组,数组的方法就是从数组的原型上继承而来的。



在JavaScript中,每个函数 都有一个prototype属性,当一个函数被用作构造函数来创建实例时,这个函数的prototype属性值会被作为原型赋值给所有对象实例(也就是设置 实例的`__proto__`属性),也就是说,所有实例的原型引用的是函数的prototype属性。


在JavaScript的原型对象中,还包含一个”constructor”属性,这个属性对应创建所有指向该原型的实例的构造函数。


”Object.prototype”的值就是”Object {}”这个原型对象。反过来,当访问”Object.prototype”对象的”constructor”这个属性的时候,就得到了Obejct函数。


另外,当通过”Object.prototype._proto_”获取Object原型的原型的时候,将会得到”null”,也就是说”Object {}”原型对象就是原型链的终点了。


Function对象作为一个函数,就会有prototype属性,该属性将对应”function () {}”对象。


Function对象作为一个对象,就有__proto__属性,该属性对应”Function.prototype”,也就是说,”Function._proto_ === Function.prototype”。


几点理解



1.Object.__proto__ === Function.prototype // true


  Object是函数对象,是通过new Function()创建,所以Object.__proto__指向Function.prototype。




2.Function.__proto__ === Function.prototype // true


  Function 也是对象函数,也是通过new Function()创建,所以Function.__proto__指向Function.prototype。




3.Function.prototype.__proto__ === Object.prototype //true


Function.prototype是个函数对象,理论上他的__proto__应该指向 Function.prototype,就是他自己,自己指向自己,没有意义,指向Object.prototype,Object.prototype.__proto__ === null,保证原型链能够正常结束。


遍历原型链


我们没有办法遍历到所有以某个对象为原型的对象,但我们可以向上遍历,获取到一个对象所有的上层原型,这个原型链必定是线性的,尽头是null。


function getPrototypeChain(object) {


    var protoChain = [];


    while (object = object.__proto__) {


        protoChain.push(object);


    }


    protoChain.push(null);


    return protoChain;


}


试验一下,不同的环境实现不同,显示形式也不同.下面是在chrome控制台中的显示.




>getPrototypeChain(new String(""))


[String, Object, null]                     //依次是String.prototype,Object.prototype,null


  


>getPrototypeChain(function(){})


[function Empty() {}, Object, null]        //依次是Function.prototype,Object.prototype,null


内置类型的对象的原型链并不长,下面试试宿主对象.




>getPrototypeChain(document.createElement("div"))


[HTMLDivElement, HTMLElement, Element, Node, Object, null]




构造超长原型链


可以看出来,我们平时使用的对象并没有很长的原型链.但可以自己构造一个.




function Foo() {}


for (var i = 0; i < 100; i++) {


    Foo.prototype["foo" + i] = i;


    Foo.prototype = new Foo;


}


console.dir(getPrototypeChain(new Foo));