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中函数与对象的关系,以及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/