更改构造函数原型的问题

时间:2011-05-31 20:05:12

标签: javascript

我目前正在阅读Stoyan Stefanov的书“面向对象的JavaScript”,我偶然发现了一个有趣的问题。这是代码:

var shape = {
    type: 'shape',
    getType: function() {
        return this.type;
    }
};

function Triangle(a, b, c) {
    this.a = a;
    this.b = b;
    this.c = c;
    this.type = 'triangle';
}

Triangle.prototype = shape; // changing the prototype object
Triangle.prototype.getPerimeter = function() {
    return this.a + this.b + this.c;
}

var t = new Triangle(1, 2, 3);
t.constructor; // logs Object() instead of Triangle(a, b, c)

正如您所看到的,这是一个构造函数的简单示例,其中包含原型对象的一些属性。但是对象t的构造函数属性指向Object()对象而不是Triangle(a,b,c),因为它应该具有。如果我用原型更改评论该行,一切正常。我的问题是什么? (重读面向对象的Javascript和JavaScript模式中的整个原型章节,找不到答案)。 附:抱歉我的英语不好,试着去练习。 :)

6 个答案:

答案 0 :(得分:6)

我将分两部分解释您的代码。首先,实际上constructor属性是什么?其次,为什么不在代码中返回Objects

constructor属性和Stoyan的错误:

在Stoyan Stefanov的书中,p150,他说:

  

prototype是一个定义函数后立即创建的属性。 其初始值为空对象。

错误。根据{{​​3}}第9.2节

  

prototype属性的初始值是具有单个属性的对象此属性名为constructor ,并引用与原型关联的构造函数。

您可以使用Triangle.prototype.constructor进行测试。它已在定义函数时设置。

结论1 constructor实际上是Constructor.prototype的属性。在您的情况下,它是Triangle.prototype.constructor

Triangle的所有实例都可以通过原型链访问此属性。 但是这些对象本身没有constructor属性。以下代码证明了这一点:

function Triangle(a, b, c) {
    this.a = a;
    this.b = b;
    this.c = c;
    this.type = 'triangle';
}
var t = new Triangle(1, 2, 3);
t.hasOwnProperty('constructor');
>>false
t.__proto__.hasOwnProperty('constructor');
>>true

结论2 :当您访问实例的constructor属性时,您可以从原型链中获取它们。

为什么它没有按预期工作

您将Triangle.prototype设置为shape 包含原始constructor属性。

因此,这次,当您查询t.constructor时,它将在以下过程中解决它:

  1. 查看它自己的属性,找不到constructor
  2. 继续关注t.__proto__Triangle.prototype。您已将其设置为shape,但不包含constructor属性。
  3. 继续沿原型链查找 - t.__proto__.__proto__。它是Triangle.prototype.__proto__,它被解析为Object.prototypeObject.prototype具有constructor属性,它引用Object

答案 1 :(得分:3)

奇怪的是,“构造函数”属性不引用该对象的构造函数。相反,它指的是对象原型的构造函数。

Here是Mozilla的相关文档页面。

答案 2 :(得分:1)

shape是一个对象,所以这样做:

Triangle.prototype = shape;

您将Triangle构造函数更改为Object

答案 3 :(得分:1)

在这里,您基本上使用基于本机/类的继承。 在Javascript中,(根据我的理解)当您使用new关键字时,您可以使用构造函数和附加的原型对象创建一个函数对象。

执行此操作时:

Triangle.prototype = shape;

您重写构造函数方法。您可以使用控制台在将形状分配到Triangle.prototype之前和之后观察对象。

当你这样做时:

t.constructor;

您无法查看您希望看到的内容,因为对构造函数方法的调用会在原型链中找到构造函数方法。

答案 4 :(得分:0)

shape不是构造函数,而是对象。它的构造函数是Object构造函数。

如果shape是构造函数,则可以设置

Triangle.prototype = new shape;

和Triangle.prototype.constructor = Triangle,以覆盖刚刚设置的shape.prototype.constructor。

答案 5 :(得分:-1)

var shape = {
    type: 'shape',
    getType: function () {
        return this.type
    }
}

function Triangle(a, b, c) {
    this.type = 'triangle'
    this.a = a;
    this.b = b;
    this.c = c;
}

Triangle.prototype = shape;
Triangle.prototype.constructor = Triangle;
Triangle.prototype.getPerimeter = function () {
    return this.a + this.b + this.c
}
var t = new Triangle(1, 2, 3)
console.log(t.constructor === Triangle) // true
console.log(shape.isPrototypeOf(t)) // true
console.log(t.getPerimeter()) // 6
console.log(t.getType()) // triangle