JavaScript原型与原型链

constructor

constructor的值是一个函数。除了nullundefined以外的值、数组、函数、对象都有constructor属性,constructor的值是这个值、数组、函数或者对象的构造函数。

调用构造函数,必须使用new

var a = 12;    a.constructor//Number(),不能直接12.constructor
'str'.constructor //String()
false.constructor //Boolean()
var a = {name : 'li'}; a.constructor // Object()
var a = [1, 'd']; a,constructor // Array()
var a = function () {}; a.constructor //Function()
var A = function () {};
var a = new A();
a.constructor //A();

但是所有的构造函数的constructor都是Function

prototype

prototype是函数的一个属性。通过构造函数构造出来的函数是没有此属性的。一个函数的默认prototype的属性值是一个与函数同名的空对象。匿名函数的prototype的值为object:

var a = function () {this.name='3'};
a.prototype // a {}

var A = function () {};
A.prototype.show = function () {};

var B = function () {};
B.prototype = A.prototype;

var test = new B();
test.constructor // A

因为B.prototype = A.prototype;把B.prototype的指向A的原型链。即A与B共同继承同一个原型链(此时,B与A共享一个原型链,但是B的实例不能访问A中声明的属性值。比如test不能访问name属性)。若只用一般的B.prototype.constructor = B;修正也不行(因为此时改变了B也就行改变了A):

var a = function () {};
a.prototype // a {}

var A = function () {};
A.prototype.show = function () {};

var B = function () {};
B.prototype = A.prototype;
B.prototype.constructor = B;

var test = new B();
test.constructor // B

var testa = new A();
testa.constructor // B 此时因为 A与B共同的原型链的构造函数 被指向了B

所以一个方法B继承A的方法为:

var a = function () {};
a.prototype // a {}

var A = function () {};
A.prototype.show = function () {};

var B = function () {};
B.prototype = new A();
B.prototype.constructor = B;

var test = new B();
test.constructor // B

var testa = new A();
testa.constructor // B

new A()是A的实例,这叫做a。即为:B.prototype = a,而a.proto指向A的原型链(A.prototype)。a作为一个对象,只继承原型链不会修改。 prototype的值是一个对象,它的构造函数也就是它的constructor属性的值就是自己函数。

A.prototype.constroctor === A //true

即 构造函数的prototype的特殊属性constructor的初始默认值为该函数。

不过往prototype添加属性与修改prototype是不一样的:

var A = function () {};
A.prototype.method1 = function () {};
var a = new A();

a.construtor === A //true

var B = function () {};
B.prototype = {
    method1 : function (){}
}
var b = new B();

b.constructor === B //false

这是因为覆盖prototype时,相当于如下:

B.prototype = new Object({
    method1:function (){};
})

此时由于constructor一直指向自身的构造函数:

B.prototype.constructor === Object

所以需要指向自己进行修正。

//再次解读: B.prototype = { method1 : function (){} }相当于new object(method1 : function (){}),这里称作obj。obj的contractor为Object。肯定与{method1 : function (){}}不等。

proto

proto属于对象的内部原型。prototype构造器的原型。

所有构造器的proto指向Function.prototype, 所有对象的proto都指向构造器的prototype。

Number.__proto__ === Function.prototype;
Boolean.__proto__ === Function.prototype;
String.__proto__ === Function.prototype;
Object.__proto__ === Function.prototype;
Function.__proto__ === Function.prototype;
Array.__proto__ === Function.prototype;
RegExp.__proto__ === Function.prototype;
Error.__proto__ === Function.prototype;
Date.__proto__ === Function.prototype;
var Person = function (){};
Person.__proto__ === Function.prototype;

只有Function.prototype的typeof Function.prototype为function,其他的typeof **.prototype 为Object。

Function.prototype 为 'function Empty()'

Function.prototype.proto === Object.prototype。而Object.prototype.proto === null

总结

每一对象都有属性,使用proto来标记,原型是一个对象的引用或null(Object.prototype.proto === null)

对象的原型来自构造函数的原型属性。

另外需要总结下,Object与Function的关系及操作。

Written on June 14, 2015