上一节提到过,通过new新建的对象的构造函数其实是该对象原型所指向的构造函数,但是不是所有的原型都有构造函数,??,通过观察比较发现,一般情况下,通过new新建的对象是没有构造函数的,在Chrome和Opera浏览器里面可以直接查看到对象是没有constructor这个属性的,奇怪不?但是实际如此(之前我还一直才猜测,但是实际上,通过new新建的对象自身是没有constructor属性的,可以通过Object.getOwnPropertyNames查看)。也就是对象的constructor属性其实是对象的原型链从对象出发向上,找到最近的有constructor的原型对象,然后这个constructor就是该对象的constructor。看看这块代码
function A() { this.name="A";} function B() { this.name="B";} function C() { this.name="C";} B.prototype = new A(); C.prototype = new B(); var a = new A(); var b = new B(); var c = new C(); console.log(a.constructor); //A() console.log(b.constructor); //A() console.log(c.constructor); //A()
为啥他们的构造函数都是A,顺着a,b,c的原型链(绿色)找,你会发现离对象最近的A.prototype有constructor属性,可能有人会问a,b,c的构造函数去那呢?上面已经强调过,正常情况下,他们本身没有constructor属性的,之所以c.constructor等有值,他是从他的原型链中找到的——即对象的原型链中离对象最近的有constructor属性的原型对象的构造函数。下面会证实这点在看看这段代码
function A() { this.name="A";} function B() { this.name="B";} function C() { this.name="C";} function A1(){ this.name="A1";} B.prototype = new A(); C.prototype = new B(); B.prototype.constructor=A1; console.log((new A()).constructor); //A() console.log((new B()).constructor); //A1() console.log((new C()).constructor); //A1()
可以发现通过B和C新建的对象的构造函数就是A1,其实就是绿色的原型链中最近的有constructor属性的原型对象的构造函数。这样可以解释很多构造函数方面的问题。
还有一个问题需要确认,如果是顺着原型链来确认构造函数,那个最终构造函数就是A
function A() { this.name="A";} function B() { this.name="B";} function C() { this.name="C";} B.prototype = new A(); C.prototype = new B(); (new C()).constructor.tname='gui'; console.log(A.tname);//gui
没错,(new C()).constructor就是A,这个不用怀疑,不然那个"gui"从哪来的呢。