Javascript 原型继承和 OOP

发布于 2024-12-15 05:48:14 字数 908 浏览 2 评论 0原文

我正在创建一个允许用户创建小部件的应用程序。有几种不同类型的小部件,我使用原型继承来定义它们。即

//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 原则?

I'm creating an application that allows a user to create widgets. There are several different types of widgets, and I have defined them using protypal inheritance. i.e.

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

I have discovered that it will be convenient to add a method on the base class that can create a new widget instance of the same type. i.e.

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

Which would allow me to get a new widget of the same type using the following code:

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

My concern is that the base widget now has to be explicitly aware of each of the types of widgets that inherit from it. Does this violate any principles of good OOP?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

痕至 2024-12-22 05:48:14
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();
};
Widget.prototype.clone = function() {
  var constructor = window[this.type];
  return new constructor();
};

Assuming that all your subclasses are declared as globals of course.

But honestly I would out those sub classes in the Widget namespace, and access them through it rather than making everything global.

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

Widget.prototype.clone = function() {
  var constructor = Widget[this.type];
  return new constructor();
};
没企图 2024-12-22 05:48:14

鉴于您的构造函数是全局的,您可以执行以下操作:

var global = this;

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

假设每个实例都有一个 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();

但是,这假设您没有任何要传递的参数。如果您确实需要传递参数,那么您可能必须知道您正在创建哪种类型,以便无论如何都可以调用正确的构造函数。

Given that your constructors are globals, you could do something like:

var global = this;

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

Provided each instance has a type property whose value is the name of the constructor. Or you could fix the constructor property of constructor's prototype and do:

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

However, that assumes that you don't have any parameters to pass. If you do have parameters to pass, then you likely have to know which type you are making and so can call the correct constructor anyway.

菊凝晚露 2024-12-22 05:48:14

如果支持 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);

If ECMA5 is supported:

  • use Object.create(Object.getPrototypeOf(this));

If ECMA5 is not supported:

  • create an anonymous function
  • set the prototype of the anonymous function to the non-standard attribute this.__proto__

Example:

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);
长安忆 2024-12-22 05:48:14

您需要的信息已在 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();

The information you need is already available in the constructor property. However, overwriting prototype will lose it as I recently explained here.

Using my own class implementation for ECMAScript version 3 or version 5, your example would look like this:

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文