1

ユーザーがウィジェットを作成できるアプリケーションを作成しています。ウィジェットにはいくつかの異なるタイプがあり、プロトタイプの継承を使用してそれらを定義しました。すなわち

//the base widget that all widgets inherit from
var Widget = function(){}        
Widget.prototype.someFunction = function(){}


//widget type A
var A = function(){}    
A.prototype = new Widget();


//widget type B
var B = function(){}    
B.prototype = new Widget();

同じタイプの新しいウィジェット インスタンスを作成できるメソッドを基本クラスに追加すると便利であることがわかりました。すなわち

//the base widget
var Widget = function(){};        

Widget.prototype.clone = function(){
    switch(this.type){
         case 'A':
             return new A();
             break;
         case 'B':
             return new B();
             break;
         default:
             break;
    }
};

次のコードを使用して、同じタイプの新しいウィジェットを取得できます。

var widgetTypeA = new A();
var cloneOfWidgetTypeA = widgetTypeA.clone();

私の懸念は、基本ウィジェットが、それから継承する各タイプのウィジェットを明示的に認識する必要があることです。これは良い OOP の原則に違反していますか?

4

4 に答える 4

2
Widget.prototype.clone = function() {
  var constructor = window[this.type];
  return new constructor();
};

もちろん、すべてのサブクラスがグローバルとして宣言されていると仮定します。

しかし、正直なところ、すべてをグローバルにするのではなく、Widget 名前空間でこれらのサブクラスを取り出し、それを介してアクセスします。

Widget.A = function(){};
Widget.A.prototype = new Widget();

Widget.prototype.clone = function() {
  var constructor = Widget[this.type];
  return new constructor();
};
于 2011-11-11T23:50:27.377 に答える
2

コンストラクターがグローバルであることを考えると、次のようなことができます。

var global = this;

Widget.prototype.clone = function() {
  if (global[this.type])
    return new global[this.type]();
};

各インスタンスには、値がコンストラクターの名前であるプロパティがあります。または、コンストラクターのプロトタイプのコンストラクター プロパティを修正して、次のようにすることもできます。

Widget.prototype.clone = function() {
    return new this.constructor();
};

function A() { };
A.prototype = new Widget();
A.prototype.constructor = A;

var a = new A();
var aa = a.clone();

ただし、これは渡すパラメータがないことを前提としています。渡すパラメーターがある場合は、作成している型を知っている必要があり、とにかく正しいコンストラクターを呼び出すことができます。

于 2011-11-12T04:04:38.970 に答える
1

ECMA5 がサポートされている場合:

  • 使用するObject.create(Object.getPrototypeOf(this));

ECMA5 がサポートされていない場合:

  • 無名関数を作成する
  • 無名関数のプロトタイプを非標準属性に設定するthis.__proto__

例:

var Widget = function() { };

Widget.prototype.clone = function() {
  /*
   Non-ECMA5: 

   var newClone = function() {};
   newClone.prototype = this.__proto__;
   return new newClone(); 
  */

  // ECMA5
  return Object.create(Object.getPrototypeOf(this));
}


var A = function() { };
A.prototype = new Widget();
A.prototype.name = "I'm an A";

var B = function() { };
B.prototype = new Widget();
B.prototype.name = "I'm a B";

var x1 = new A();
var y1 = x1.clone();

console.log("y1 should be A: %s", y1.name);

var x2 = new B();
var y2 = x2.clone();

console.log("y2 should be B: %s", y2.name);
于 2011-11-12T00:10:30.003 に答える
1

必要な情報は、constructorプロパティで既に利用可能です。ただし、最近ここで説明したように、上書きprototypeすると失われます。

ECMAScriptバージョン 3またはバージョン 5の独自のクラス実装を使用すると、例は次のようになります。

var Widget = Class.extend({
    someFunction : function() {
        alert('someFunction executed');
    },

    clone : function() {
        return new this.constructor;
    }
});

var A = Widget.extend();

var B = Widget.extend({
    constructor : function(arg) {
        Widget.call(this); // call parent constructor
        this.arg = arg;
    },

    // override someFunction()
    someFunction : function() {
        alert('someFunction executed, arg is ' + this.arg)
    },

    // clone() needs to be overriden as well:
    // Widget's clone() doesn't know how to deal with constructor arguments
    clone : function() {
        return new this.constructor(this.arg);
    }
});

var a = new A;
var a2 = a.clone();
a2.someFunction();

var b = new B(42);
var b2 = b.clone();
b2.someFunction();
于 2011-11-12T13:27:08.250 に答える