JavaScript中函数的prototype原型对象的constructor为什么明明已经改过来了,但new出来的对象中的constructor却还是原来的?
具体请看下面的代码和注释:
function CreateObject(pPrototypeClass, pParams) { function Temp() { pPrototypeClass.Create.apply(this, pParams); alert('2.Temp.prototype.constructor: ' + Temp.prototype.constructor); //此时Temp.prototype.constructor为Temp函数本身 Temp.prototype = pPrototypeClass; alert('3.Temp.prototype.constructor: ' + Temp.prototype.constructor); //此时Temp.prototype.constructor已变为Object函数 }; alert('1.Temp.prototype.constructor: ' + Temp.prototype.constructor); //此时Temp.prototype.constructor为Temp函数本身 alert('pPrototypeClass.constructor: ' + pPrototypeClass.constructor); //pPrototypeClass.constructor为Object函数 return new Temp(); }; var PersonPrototypeClass = { Create: function(pName, pAge) { this.name = pName; this.age = pAge; }, SayHello: function() { alert("Hello, I'm " + this.name); }, HowOld: function() { alert(this.name + " is " + this.age + " years old."); } }; var oPerson = CreateObject(PersonPrototypeClass, ["Bill Gates", 53]); alert('oPerson.constructor: ' + oPerson.constructor); //这里oPerson.constructor却仍然是Temp函数!为什么?前面Temp.prototype.constructor不是已改为Object函数了吗? alert(oPerson.constructor == Object); //为false,按道理应该为true
但如果把Temp函数的这一句Temp.prototype = pPrototypeClass;移动到外层函数CreateObject中,如下:
function CreateObject(pPrototypeClass, pParams) { function Temp() { pPrototypeClass.Create.apply(this, pParams); alert('3.Temp.prototype.constructor: ' + Temp.prototype.constructor); //此时Temp.prototype.constructor已变为Object函数 }; alert('1.Temp.prototype.constructor: ' + Temp.prototype.constructor); //此时Temp.prototype.constructor为Temp函数本身 Temp.prototype = pPrototypeClass; alert('2.Temp.prototype.constructor: ' + Temp.prototype.constructor); //此时Temp.prototype.constructor已变为Object函数 alert('pPrototypeClass.constructor: ' + pPrototypeClass.constructor); //pPrototypeClass.constructor为Object函数 return new Temp(); }; var PersonPrototypeClass = { Create: function(pName, pAge) { this.name = pName; this.age = pAge; }, SayHello: function() { alert("Hello, I'm " + this.name); }, HowOld: function() { alert(this.name + " is " + this.age + " years old."); } }; var oPerson = CreateObject(PersonPrototypeClass, ["Bill Gates", 53]); alert('oPerson.constructor: ' + oPerson.constructor); //这里oPerson.constructor已变为Object函数 alert(oPerson.constructor == Object); //为true
为什么Temp.prototype = pPrototypeClass;这句语句在Temp函数体内和移动到外层函数体内,结果就不一样呢?
———————————————————————————————————————————
20151209补充:
感谢各位的回答,每位答主都从不同角度部分地解答了我的部分疑惑。现在我的看法是,关键在于new一个构造函数的时候,到底发生了什么?下面总结一下我现在的理解。new一个构造函数的时候,依次发生了如下三个步骤:
1)创建一个空的新对象。
2)将新对象的隐式原型属性__proto__赋值为构造函数的显式原型属性prototype,即新对象.__proto__ = 构造函数.prototype。
3)执行构造函数,并且同时将构造函数中的this指向新对象,即构造函数.call(新对象)。
因此,new一个构造函数时,是先将该构造函数的prototype赋值给新对象的__proto__,然后才执行构造函数;而不是先执行构造函数,然后才赋值prototype。这两个步骤的顺序,才是问题中前后两段代码的运行结果不同的原因。
再次感谢各位的回答!
这个结果不一样这是正常的,你放在里面的时候,在你n做new动作之前你还没有改变Temp.prototype,new 动作在之前,new temp 就是在操作prototype。你这个是没有变化的,另外new 动作之后 做Temp.prototype 只是动态改变了Temp.prototype的属性。constructor 还是Temp。
并且 就算你改变了Temp.prototype,你也没有返回 已经坐更改的Temp,当然此刻按照你的写法返回Temp 的实例 就是一个死循环了。 你可以断点跟踪一下 当你改变了Temp.prototype,然后再new出来的对象 已经发生了变化了
好长的代码啊,第一个
oPerson.constructor
指向的是Temp函数,你的疑惑应该是在Temp.prototype = pPrototypeClass;
,不是将Temp.prototype
更改了吗,但是事情并不是你想的这样的啊,你这样是将Temp.prototype
赋值为了另外一个对象,这样就阻断了它与oPerson
对象的关系,因为oPerson
的__proto__
属性指向的仍然是你原来在堆中存的那个对象,来看下面这段代码你就会明白:下面那个为什么是
true
的原因也很简单,因为你在应用构造函数之前就将这个函数的原型地址给改了,你使用构造函数时,他们指向的一块内存。