js的__proto__,prototype、constructor属性

根据JavaScript核心以及原文JavaScript. The core.加上自己的理解做一个总结。

prototype与__proto__、constructor理解

  • prototype是每个函数都有的属性,它指向的是一个(原型)对象,是创建原型链的重要属性;

  • __proto__描述实例化对象与其原型对象之间的关系,每一个对象均可看成另一个对象的实例对象,故每一个对象都有__proto__属性;

  • constructor是每个原型对象都有的属性,始终指向创建该对象(自身)的构造函数,每一个函数都有prototype属性,prototype.constructor指向该构造函数。

以内置对象Object()为例:

    var obj=new Object();  
    typeof obj.__proto__;//"object"  
    obj.__proto__===Object.prototype;//true  
    obj.constructor;//function Object(){native code}  
    Object.prototype.constructor===obj.constructor;//true  

  obj是构造函数Object()的实例化对象,则必然有__proto__属性指向构造该实例对象的原型即Object.prototype,也是一个对象。

流程图

  可以从结果知道obj.constructor指向了obj对象的构造函数Object(),然而这并不表明obj自身有constructor属性,而是根据原型链向上查找。当自身没有找到属性,就会查找obj.__proto__,就是Object.prototype,从而找到constructor属性,由Object.prototype.constructor===obj.constructor;返回true就可以知道。

内置函数与Function.prototype的关系

js原型链

这个图表明了整个js中函数与对象的关系,以及prototype、__proto__、constructor的指向。

  由上图可以知道,Object()其实也是一个Function()函数的实例化对象,也有__proto__属性,指向Function.prototype从而形成了原型链。

W3C中对Math对象有如下注释:

Math 对象并不像 Date 和 String 那样是对象的类,因此没有构造函数 Math(),像 Math.sin() 这样的函数只是函数,不是某个对象的方法。您无需创建它,通过把 Math 作为对象使用就可以调用其所有属性和方法。

在控制台运行以下代码,以Object()、Array()、以及Math对象为例:

    Object.__proto__===Function.prototype;//true
    Object.constructor;//function Function(){native code}
    Object.constructor===Object.__proto__.constructor;//true
    Array.__proto__===Function.prototype;//true
    Array.constructor;//function Function(){native code}
    Array.constructor===Array.__proto__.constructor;//true
    Math.__proto__===Object.prototype;//true
    Math.prototype;//undefined
    Math.constructor;//function Object(){native code}
    Math.constructor===Math.__proto__.constructor;//true
  • 除了Math对象以外,其他的内置对象均是Function通过new创建出来的,也是函数,既然是函数则肯定有prototype属性,它所指向的是它们自身的原型函数Array.prototype,String.prototype等。

  • 它们的__proto__属性均指向它们构造函数的原型Function.prototype。它们的constructor属性均指向它们的构造函数function Function(){...};

  • Math对象虽然没有prototype属性,但是它也有__proto__属性,指向Object.prototype。

注意:实例化对象自身是没有constructor属性,是从其__proto__原型中继承过来的。

Function()函数是通过new自己本身创建出来的,Function.__proto__指向的是Function.prototype,Function.constructor指向的是function Function(){...}。

Function.prototype与Object.prototype的关系

  由上面可以知道内置对象(除Math)的__proto__属性都指向Function.prototype,那Function.prototype呢?
在控制台运行以下代码:

    typeof Function.prototype;//function
    Function.prototype.prototype;//undefined
    Function.prototype.__proto__===Object.prototype;//true
    typeof Object.prototype;//"object"
    Object.prototype.__proto__;//null

可以看出Function.prototype其实是一个函数,但是它的prototype指向的值却是undefined,这算是一个特例。Function.prototype的__proto__属性指向Object.prototype。

所有的对象原型包括函数对象原型最终都指向Object.prototype,而Object.prototype的__proto__指向null

普通函数和对象的prototype、__proto__、constructor

  自定义构造函数Test(),查看它的prototype、__proto__、constructor:

    function Test(num1,num2){
         this.n1=num1;
         this.n2=num2;
    }
    var obj=new Test();

结果如下:
结果

object.prototype形成了原型链;Test.__proto__指向构造函数Function()的原型Function.prototype,而Function.prototype.__proto__指向Object.prototype也形成了原型链;Test.prototype的constructor属性指向了构造该对象原型的构造函数function Test()。

总结:

  • 每一个函数都有prototype属性,可以指向一个对象或者null;

  • __proto__描述实例化对象与其原型对象之间的关系,每一个对象均可看成另一个对象的实例对象,故每一个对象都有__proto__属性;

  • 每一个function.prototype对象默认有一个属性constructor,且constructor始终指向创建该对象原型的构造函数;

  • 所有内置对象中,除了Math对象没有构造函数以外,其余所有内置对象均为Function()函数通过new创建出来的实例化对象,Function()函数是通过new自己本身创建出来的,Function.__proto__指向的是Function.prototype,Function.constructor指向的是function Function(){...}。

  • Function.prototype是一个函数,但它是个特例,没有prototype属性。


参考

1:http://weizhifeng.net/javascript-the-core.html
2:http://dmitrysoshnikov.com/ecmascript/javascript-the-core/

posted @ 2017-05-12 09:58  艾新觉罗  阅读(428)  评论(0编辑  收藏  举报