JavaScript中函数的prototype原型的constructor的奇怪问题?

笨笨阿林
  • 272

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。这两个步骤的顺序,才是问题中前后两段代码的运行结果不同的原因。

再次感谢各位的回答!

回复
阅读 2.8k
2 个回答

这个结果不一样这是正常的,你放在里面的时候,在你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__属性指向的仍然是你原来在堆中存的那个对象,来看下面这段代码你就会明白:


function Temp () {
    this.name = "zp";
}
Temp.prototype.age = 19;
var obj = new Temp();
Temp.prototype = {
    age: 20
};
console.log(obj.__proto__);  // {age: 19}

下面那个为什么是true的原因也很简单,因为你在应用构造函数之前就将这个函数的原型地址给改了,你使用构造函数时,他们指向的一块内存。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏