混淆JavaScript原型继承与构造函数 [英] Confused about JavaScript prototypal inheritance with constructors

查看:91
本文介绍了混淆JavaScript原型继承与构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 函数卡(值){
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对象这种方式,它是复制构造函数代码。我应该使用原型继承,但这不工作:

  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 code>。相反,我必须调用 var card1 = new Card(); card1.setValue(); 这似乎对我来说是非常低效和丑陋。但真正的问题是它将每个Card对象的value属性设置为相同的值。帮助!






编辑



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

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

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

this.value = value;
};

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

这导致三个Card对象具有随机值,这是伟大的,我可以调用setValue方法稍后的。当我尝试扩展类时,似乎没有转移:

  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不是一个函数现在。






编辑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帮助我识别为什么我不能继承原型链, Norguard解释了为什么最好不要使用原型链。我喜欢这种方法,因为代码更干净,更容易理解。

解决方案


它是每次我创建一个新的Card对象这种方式,它是复制构造函数代码


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



问题只会在你创建值时出现。每个函数的调用创建它自己的一组值,例如。私有变量(你没有任何)。他们通常会收集垃圾,除非你创建另一个特殊的值,一个特权方法,这是一个暴露的函数,它保存对它所存在的范围的引用。是的,每个对象都有自己的副本这样的函数,这就是为什么你应该推一切不访问私有变量的原型。

  Object.defineProperty Card,value,... 

等待,不,在构造函数中定义一个属性,函数 Card 这不是你想要的,你可以在实例上调用这个代码,是的,但是注意当评估 this.value = value; 它将递归调用自身。

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

这看起来不错,你可以在 / code>对象,当你打算使用验证代码,例如当更改 Card 实例的值(我不这么认为,但我不知道?)。


但是我不能再呼叫新的Card()


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

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





是的,它没有。调用构造函数不会设置原型链。使用 关键字具有其继承的对象被实例化,然后应用构造函数。用你的代码, SpecialCard 继承自 SpecialCard.prototype 对象(它自身继承了默认的对象原型)。现在,我们可以将其设置为与正常卡片相同的对象,或者让它从该卡继承。

  SpecialCard。 prototype = Card.prototype; 

现在每个实例都继承自同一个对象。这意味着, SpecialCard 将没有特殊的方法(从原型)正常没有。 ..此外, instanceof 操作符将无法正常工作。



因此,有一个更好的解决方案。让 SpecialCard 的原型对象继承自 Card.prototype !这可以使用 Object.create (不受所有浏览器支持,您可能需要解决方法),其目的是完成这项工作:

  SpecialCard .prototype = Object.create(Card.prototype,{
constructor:{value:SpecialCard}
});
SpecialCard.prototype.specialMethod = ... //现在可能


I've read pages and pages about JavaScript prototypal inheritance, but I haven't found anything that addresses using constructors that involve validation. I've managed to get this constructor to work but I know it's not ideal, i.e. it's not taking advantage of prototypal inheritance:

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();

This results in three Card objects with random values. However, the way I understand it is that each time I create a new Card object this way, it is copying the constructor code. I should instead use prototypal inheritance, but this doesn't work:

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;
    }
});

This doesn't work either:

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

    this.value = value;
};

For one thing, I can no longer call new Card(). Instead, I have to call var card1 = new Card(); card1.setValue(); This seems very inefficient and ugly to me. But the real problem is it sets the value property of each Card object to the same value. Help!


Edit

Per Bergi's suggestion, I've modified the code as follows:

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();

This results in three Card objects with random values, which is great, and I can call the setValue method later on. It doesn't seem to transfer when I try to extend the class though:

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");

I get the error this.setValue is not a function now.


Edit 2

This seems to work:

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

    this.suit = suit;
}

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

Is this a good way to do it?


Final Edit!

Thanks to Bergi and Norguard, I finally landed on this implementation:

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 helped me identify why I wasn't able to inherit the prototype chain, and Norguard explained why it's better not to muck with the prototype chain at all. I like this approach because the code is cleaner and easier to understand.

解决方案

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

No, it is executing it. No problems, and your constructor works perfect - this is how it should look like.

Problems will only arise when you create values. Each invocation of a function creates its own set of values, e.g. private variables (you don't have any). They usually get garbage collected, unless you create another special value, a privileged method, which is an exposed function that holds a reference to the scope it lives in. And yes, every object has its own "copy" of such functions, which is why you should push everything that does not access private variables to the prototype.

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

Wait, no. Here you define a property on the constructor, the function Card. This is not what you want. You could call this code on instances, yes, but note that when evaluating this.value = value; it would recursively call itself.

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

This looks good. You could need this method on Card objects when you are going to use the validation code later on, for example when changing the value of a Card instance (I don't think so, but I don't know?).

but then I can no longer call new Card()

Oh, surely you can. The method is inherited by all Card instances, and that includes the one on which the constructor is applied (this). You can easily call it from there, so declare your constructor like this:

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

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

Yes, it does not. Calling the constructor function does not set up the prototype chain. With the new keyword the object with its inheritance is instantiated, then the constructor is applied. With your code, SpecialCards inherit from the SpecialCard.prototype object (which itself inherits from the default Object prototype). Now, we could either just set it to the same object as normal cards, or let it inherit from that one.

SpecialCard.prototype = Card.prototype;

So now every instance inherits from the same object. That means, SpecialCards will have no special methods (from the prototype) that normal Cards don't have... Also, the instanceof operator won't work correctly any more.

So, there is a better solution. Let the SpecialCards prototype object inherit from Card.prototype! This can be done by using Object.create (not supported by all browsers, you might need a workaround), which is designed to do exactly this job:

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

这篇关于混淆JavaScript原型继承与构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆