【问题标题】:Use of prototype constructor in JSJS中原型构造函数的使用
【发布时间】:2011-07-30 17:35:58
【问题描述】:

有人可以向我解释Me.prototype.constructor = Me; 的用法以及为什么需要此代码,什么时候可以正常工作而没有它?

在代码中,原型对象是在 Me 对象上创建的,它被实例化并替换旧的原型对象。为什么我需要在给定的代码中指向 Me 构造函数?

function Me(){
    this.name = 'Dejan';

}

function You(){
    this.name = 'Ivan';
}

Me.prototype = new You();

somebody = new Me();

Me.prototype.constructor = Me; // Why?

Me.prototype.foo = function(){
    alert('Proto Me!'); // It always fire up this alert, ether constructor is pointing to Me or not... !
}

You.prototype.foo = function(){
    alert('Proto You!');
}

somebody.foo();
alert(somebody.name); // Alert 'Dejan'

【问题讨论】:

  • 我相信旧版浏览器会检查 .constructor 属性中的 instanceof 关键字。

标签: javascript oop


【解决方案1】:

它不需要,instanceof 甚至不需要它,这与流行的看法相反(instanceof 内部检查原型链并且不需要构造函数属性)。通常,constructor 本质上是构造函数prototype 上的不可枚举属性。因此,为由该构造函数实例化的任何对象提供一个指向该构造函数的不可枚举的constructor 属性。

如果需要,最好把它放在那里,理想情况下是不可枚举的。一些代码会假设对象上存在.constructor

在您发布的代码中,是的,当以这种方式进行继承时,有必要重置构造函数(如果您想要它在那里),因为您实例化作为子原型的对象具有指向错误构造函数的构造函数属性(它的构造函数)。

在 ES5 中,你会这样做:

Child.prototype = Object.create(Parent.prototype, {
  constructor: { value: Child, enumerable: false }
});

编辑:另外,可能值得一提的是,当使用非标准__proto__ 进行继承时,没有必要重置构造函数,因为__proto__ 仅指定对象的原型,也就是说,查找对象的对象将在自己的属性不存在时执行。新的prototype 将始终有一个名为constructor 的属性。

这样做:

var child = function() {};
child.prototype.__proto__ = parent.prototype;

您不必设置构造函数,因为 child.prototype 的基本构造函数属性仍然存在。如果访问,则无需执行原型链查找。

【讨论】:

  • 你确定 IE6 不检查constructor 属性吗? Object.create 为您设置 constructor 属性。您不必手动操作
  • Raynos,不,我不确定 IE6,因为我并不真正关心 IE6。还有,Object.create 没有给你设置构造函数,它没有构造函数的概念,其实这就是Object.create 的意义所在。你只会得到一个等于父构造函数的构造函数属性,这对于继承来说是错误的。所以你需要改变它。
  • 你对 constructor 的看法是对的。 Object.create 没有构造函数的概念
【解决方案2】:

如果换行

Me.prototype.constructor = Me; // Why?

console.log(Me.prototype.constructor);
Me.prototype.constructor = Me; // Why?

你会发现在设置之前Me.prototype.constructor就是You,因为Me.prototypeYou的一个实例,因为这条线

Me.prototype = new You();

因此,// Why? 注释行是必要的,以“纠正”这种错误印象,即您通过这种方式继承给 JavaScript。


本质上,问题的出现是因为您试图使用原型继承来实现经典继承。原型继承适用于对象实例,并且没有“类”甚至实际上是“类型”的概念,但 JavaScript 让整个 new.constructorinstanceof 业务更加混乱。

做这种事情的一个更典型的方式是避开构造函数,转而使用强力构造函数,即返回具有您想要的形式的对象的函数:

function begetPart(partNumber,  description) {
    return Object.create({}, {
        number: { value: partNumber },
        description: { value: description },
        describe: {
            value: function () {
                alert(this.description);
            }
        }
    });
}

function begetTire(partNumber, speed) {
    return Object.create(
        begetPart(partNumber, "A tire"),
        {
            speed: { value: speed },
            describe: {
                value: function () {
                    alert(this.description + "; speed = " + this.speed);
                }
            }
        }
    );
}

var genericPart = begetPart(1234, "A widget");
genericPart.describe(); // alerts "A widget"

var tire = begetTire(4567, "fast");
tire.describe(); // alerts "A tire; speed = fast"

这里我们使用Object.create 表示“基于这个其他对象实例创建一个对象实例”。另一个实例是 begetPart 的一个新的空对象和一个新的“部件实例”,其中为 begetTire 预填充了一些属性。

这更好地反映了 JavaScript 和原型继承的实际工作方式,因为在原型继承中,对象实例从其他对象实例继承,而没有整个“类型”或“类”的想法妨碍。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-06
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多