更改构造函数原型时出现问题

Problems with changing constructor's prototype

本文关键字:问题 原型 构造函数      更新时间:2023-09-26

我目前正在阅读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模式中的整个原型章节,找不到答案(。附言对不起我的英语不好,试图练习它。:)

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

constructor属性和斯托扬的错误:

在斯托扬·斯特凡诺夫(Stoyan Stefanov(的书第150页中,他说:

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

这是错误的。根据 JavaScript 权威指南第 9.2 节

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

您可以使用 Triangle.prototype.constructor .它是在定义函数时设置的。

结论1constructor实际上是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设置为不包含原始constructor属性的shape

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

  1. 看看它自己的属性,找不到constructor
  2. 继续仰望t.__proto__,这是Triangle.prototype。已将其设置为不包含 constructor 属性的shape
  3. 继续沿着原型链向上查找 - t.__proto__.__proto__ .它是Triangle.prototype.__proto__的,它被解析为Object.prototypeObject.prototype具有constructor属性,它指的是Object

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

这是来自Mozilla的相关文档页面。

shape是一个

对象,所以通过这样做:

Triangle.prototype = shape;

将构造函数更改为Triangle Object

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

执行此操作时:

Triangle.prototype = shape;

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

然后执行此操作时:

t.constructor;

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

形状不

是一个构造函数,而是一个对象。它的构造函数是对象构造函数。

如果形状是您可以设置的构造函数

三角形原型=新形状;

和 Triangle.prototype.constructor

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

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