gpt4 book ai didi

javascript - 对 JavaScript 原型(prototype)继承与构造函数感到困惑

转载 作者:行者123 更新时间:2023-11-29 18:27:26 24 4
gpt4 key购买 nike

我已经阅读了很多关于 JavaScript 原型(prototype)继承的页面,但我还没有找到任何关于使用涉及验证的构造函数的内容。我已经设法让这个构造函数工作,但我知道它并不理想,即它没有利用原型(prototype)继承:

function Card(value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}

this.value = value;
}

var card1 = new Card();
var card2 = new Card();
var card3 = new Card();

这会产生三个具有随机值的 Card 对象。然而,我的理解是,每次我以这种方式创建一个新的 Card 对象时,它都是在复制构造函数代码。我应该改为使用原型(prototype)继承,但这不起作用:

function Card(value) {
this.value = value;
}

Object.defineProperty( Card, "value", {
set: function (value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}

this.value = value;
}
});

这也行不通:

Card.prototype.setValue = function (value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}

this.value = value;
};

一方面,我不能再调用 new Card()。相反,我必须调用 var card1 = new Card(); card1.setValue(); 这对我来说似乎非常低效和丑陋。但真正的问题是它将每个 Card 对象的 value 属性设置为相同的值。帮助!


编辑

根据 Bergi 的建议,我修改了代码如下:

function Card(value) {
this.setValue(value);
}

Card.prototype.setValue = function (value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}

this.value = value;
};

var card1 = new Card();
var card2 = new Card();
var card3 = new Card();

这会产生三个具有随机值的 Card 对象,这很好,我可以稍后调用 setValue 方法。但是,当我尝试扩展类(class)时,它似乎并没有转移:

function SpecialCard(suit, value) {
Card.call(this, value);

this.suit = suit;
}

var specialCard1 = new SpecialCard("Club");
var specialCard2 = new SpecialCard("Diamond");
var specialCard3 = new SpecialCard("Spade");

我现在收到错误 this.setValue is not a function


编辑2

这似乎可行:

function SpecialCard(suit, value) {
Card.call(this, value);

this.suit = suit;
}

SpecialCard.prototype = Object.create(Card.prototype);
SpecialCard.prototype.constructor = SpecialCard;

这样做好吗?


最终编辑!

感谢 Bergi 和 Norguard,我终于找到了这个实现:

function Card(value) {
this.setValue = function (val) {
if (!isNumber(val)) {
val = Math.floor(Math.random() * 14) + 2;
}

this.value = val;
};

this.setValue(value);
}

function SpecialCard(suit, value) {
Card.call(this, value);

this.suit = suit;
}

Bergi 帮助我确定了为什么我无法继承原型(prototype)链,Norguard 解释了为什么最好不要弄乱原型(prototype)链。我喜欢这种方法,因为代码更清晰、更容易理解。

最佳答案

the way I understand it is that each time I create a new Card object this way, it is copying the constructor code

不,它正在执行它。没问题,您的构造函数工作完美 - 这就是它应该的样子。

问题只有在你创造值(value)的时候才会出现。函数的每次调用都会创建自己的一组值,例如私有(private)变量(你没有)。它们通常会被垃圾回收,除非您创建另一个特殊值,一个特权方法,它是一个公开的函数,持有对其所在范围的引用。是的,每个对象都有自己的“副本” "的此类函数,这就是为什么您应该将不访问私有(private)变量的所有内容推送到原型(prototype)。

 Object.defineProperty( Card, "value", ...

等等,不。在这里,您在构造函数上定义了一个属性,函数 Card。这不是你想要的。您可以在实例上调用此代码,是的,但请注意,在评估 this.value = value; 时,它会递归地调用自身。

 Card.prototype.setValue = function(){ ... }

这看起来不错。当您稍后要使用验证代码时,您可能需要在 Card 对象上使用此方法,例如在更改 Card 实例的值时(我不认为所以,但我不知道?)。

but then I can no longer call new Card()

哦,当然可以。该方法由所有 Card 实例继承,包括应用构造函数的实例 ( this )。你可以很容易地从那里调用它,所以像这样声明你的构造函数:

function Card(val) {
this.setValue(val);
}
Card.prototype...

It doesn't seem to transfer when I try to extend the class though.

是的,它没有。调用构造函数不会建立原型(prototype)链。随着new keyword实例化其继承的对象,然后应用构造函数。使用您的代码,SpecialCard 继承自 SpecialCard.prototype 对象(它本身继承自默认的 Object 原型(prototype))。现在,我们可以将它设置为与普通卡片相同的对象,或者让它继承那个对象。

SpecialCard.prototype = Card.prototype;

所以现在每个实例都继承自同一个对象。这意味着,SpecialCard 将没有普通 Card 没有的特殊方法(来自原型(prototype))...另外,instanceof operator将无法再正常工作。

所以,有一个更好的解决方案。让 SpecialCard 的原型(prototype)对象继承自 Card.prototype!这可以通过使用 Object.create 来完成(并非所有浏览器都支持,您可能需要 workaround ),它的设计正是为了完成这项工作:

SpecialCard.prototype = Object.create(Card.prototype, {
constructor: {value:SpecialCard}
});
SpecialCard.prototype.specialMethod = ... // now possible

关于javascript - 对 JavaScript 原型(prototype)继承与构造函数感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11662573/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com