5

JavaScript に問題があります。私は次のコードを持っています:

<html>
<head>
<title>Test</title>
<script  type="text/javascript">
function Control(){
    var name;

    this.setName = function(newName){
        name = newName;
    };

    this.getName = function(){
        return name;
    };
}

function SpecializedControl(){
}
SpecializedControl.prototype = new Control();

function Form(){
    var formControls = [];

    this.addControl = function(control){
         formControls.push(control);

         alert(formControls[0].getName());
    };
}

var form = new Form();

var control1 = new SpecializedControl();
control1.setName("Control1");
form.addControl(control1);

var control2 = new SpecializedControl();
control2.setName("Control2");
form.addControl(control2);

</script>
</head>
<body>
</body>
</html>

SpecializedControl は Control クラスを継承します。

Form クラスの addControl 関数は、コントロールを配列に追加するだけです。

問題は、複数の SpecializedControl を追加すると、配列内の値が一種のオーバーライドされることです。つまり、配列内の最初の項目 ("Control1" である必要があります) にアクセスすると、"Control2" が取得されます。Control1 はもう配列にありません。

Control オブジェクトで同じ関数をパラメーターとして使用すると、すべてが期待どおりに機能します。

なぜこれが起こるのか、これを修正するために何ができるのか誰かが知っていますか?

4

2 に答える 2

5

配列内の値はオーバーライドされていません。問題は、両方のコントロールが同じname変数を共有していることです。Control関数は 1 回しか実行されないため、name宣言された変数は 1 つだけです。

これを修正するには、主に 2 つのオプションがあります。(1)name個々のコントロールに固有のインスタンス変数を作成します (例: this._name)。(2)コンストラクタControl内から関数を実行します。SpecializedControl(実際には、IMO、バランスのとれた完全な継承モデルのために、これらの両方の方法を少し実行する必要があります)。

ここに3つの実用的なソリューションがあります。最初の 2 つは、それぞれオプション (1) と (2) を使用します。3番目は両方の方法を組み合わせたもので、私が行う方法です(ただし、joiが必要です)。

オプション1:

function Control(){

    this.setName = function(newName){
        this._name = newName;
    };

    this.getName = function(){
        return this._name;
    };
}

オプション 2:

function SpecializedControl(){
    Control.apply(this, arguments);
}

オプション 3:

var Control = joi.Unit.sub(function() {

    function constructor() {
        this.base();
    }

    constructor.prototype = {
        '#name': null,
        setName: function(name) {
            this['#name'] = name;
        },
        getName: function() {
            return this['#name'];
        }
    };

    return constructor;

}());

var SpecializedControl = Control.sub(function() {

    function constructor() {
        this.base();
    }

    return constructor;

}());

var Form = joi.Unit.sub(function() {

    function constructor() {
        this.base();
        this['#formControls'] = [];
    }

    constructor.prototype = {
        '#formControls': null,
        addControl: function(control) {
            this['#formControls'].push(control);
            alert(this['#formControls'][0].getName());
        }
    };

    return constructor;

}());

var form = new Form();

var control1 = new SpecializedControl();
control1.setName("Control1");
form.addControl(control1);

var control2 = new SpecializedControl();
control2.setName("Control2");
form.addControl(control2);​
于 2012-06-12T22:32:26.960 に答える
5

関数は、コンストラクター関数に対してローカルな変数get/setNameの値を取得/設定しています。nameControl

その関数を呼び出したのは、 のprototypeオブジェクトとしてインスタンスを作成したときだけですSpecializedControlsetNameしたがって、インスタンスから呼び出すたびSpecializedControlに、その単一の変数が更新されます。

したがって、get/setNameその変数を参照するメソッドはすべてのSpecializedControlインスタンスのプロトタイプ チェーンにあるため、それらはすべて同じname.


ではsetName、次のことを行う必要があります...

this.name = newName;

そしてgetName、あなたがすべきこと...

return this.name;
于 2012-06-12T22:23:59.153 に答える