将基于类的设计应用于JavaScript程序是一种不好的做法吗?
JavaScript是一种基于原型的语言,但它能够模仿基于类的面向对象语言的一些特性。例如,JavaScript没有公共和私有成员的概念,但通过闭包的魔力,仍然可以提供相同的功能。类似地,方法重载、接口、名称空间和抽象类都可以以这样或那样的方式添加 最近,由于我一直在用JavaScript编程,我觉得我正在尝试将它变成一种基于类的语言,而不是按照它应该使用的方式使用它。似乎我在试图迫使语言符合我的习惯 下面是我最近编写的一些JavaScript代码。它的目的是将绘制HTML5画布元素所涉及的一些工作抽象出来将基于类的设计应用于JavaScript程序是一种不好的做法吗?,javascript,Javascript,JavaScript是一种基于原型的语言,但它能够模仿基于类的面向对象语言的一些特性。例如,JavaScript没有公共和私有成员的概念,但通过闭包的魔力,仍然可以提供相同的功能。类似地,方法重载、接口、名称空间和抽象类都可以以这样或那样的方式添加 最近,由于我一直在用JavaScript编程,我觉得我正在尝试将它变成一种基于类的语言,而不是按照它应该使用的方式使用它。似乎我在试图迫使语言符合我的习惯 下面是我最近编写的一些JavaScript代码。它的目的是将绘制HTML5画布元素所涉及的一些
/*
Defines the Drawing namespace.
*/
var Drawing = {};
/*
Abstract base which represents an element to be drawn on the screen.
@param The graphical context in which this Node is drawn.
@param position The position of the center of this Node.
*/
Drawing.Node = function(context, position) {
return {
/*
The method which performs the actual drawing code for this Node. This method must be overridden in any subclasses of Node.
*/
draw: function() {
throw Exception.MethodNotOverridden;
},
/*
Returns the graphical context for this Node.
@return The graphical context for this Node.
*/
getContext: function() {
return context;
},
/*
Returns the position of this Node.
@return The position of this Node.
*/
getPosition: function() {
return position;
},
/*
Sets the position of this Node.
@param thePosition The position of this Node.
*/
setPosition: function(thePosition) {
position = thePosition;
}
};
}
/*
Define the shape namespace.
*/
var Shape = {};
/*
A circle shape implementation of Drawing.Node.
@param context The graphical context in which this Circle is drawn.
@param position The center of this Circle.
@param radius The radius of this circle.
@praram color The color of this circle.
*/
Shape.Circle = function(context, position, radius, color) {
//check the parameters
if (radius < 0)
throw Exception.InvalidArgument;
var node = Drawing.Node(context, position);
//overload the node drawing method
node.draw = function() {
var context = this.getContext();
var position = this.getPosition();
context.fillStyle = color;
context.beginPath();
context.arc(position.x, position.y, radius, 0, Math.PI*2, true);
context.closePath();
context.fill();
}
/*
Returns the radius of this Circle.
@return The radius of this Circle.
*/
node.getRadius = function() {
return radius;
};
/*
Sets the radius of this Circle.
@param theRadius The new radius of this circle.
*/
node.setRadius = function(theRadius) {
radius = theRadius;
};
/*
Returns the color of this Circle.
@return The color of this Circle.
*/
node.getColor = function() {
return color;
};
/*
Sets the color of this Circle.
@param theColor The new color of this Circle.
*/
node.setColor = function(theColor) {
color = theColor;
};
//return the node
return node;
};
/*
定义图形名称空间。
*/
变量绘图={};
/*
表示要在屏幕上绘制的元素的抽象基。
@param在其中绘制此节点的图形上下文。
@param position此节点中心的位置。
*/
Drawing.Node=函数(上下文、位置){
返回{
/*
为此节点执行实际绘图代码的方法。此方法必须在节点的任何子类中重写。
*/
绘图:函数(){
抛出Exception.MethodNotOverrided;
},
/*
返回此节点的图形上下文。
@返回此节点的图形上下文。
*/
getContext:function(){
返回上下文;
},
/*
返回此节点的位置。
@返回此节点的位置。
*/
getPosition:function(){
返回位置;
},
/*
设置此节点的位置。
@参数位置此节点的位置。
*/
设置位置:功能(位置){
位置=位置;
}
};
}
/*
定义形状名称空间。
*/
var Shape={};
/*
Drawing.Node的圆形实现。
@参数上下文绘制此圆的图形上下文。
@参数定位此圆的中心。
@参数半径此圆的半径。
@praram color这个圆圈的颜色。
*/
圆形=函数(上下文、位置、半径、颜色){
//检查参数
如果(半径<0)
抛出Exception.InvalidArgument;
变量节点=绘图节点(上下文、位置);
//重载节点绘制方法
node.draw=函数(){
var context=this.getContext();
var position=this.getPosition();
context.fillStyle=颜色;
context.beginPath();
弧(位置x,位置y,半径0,数学PI*2,真);
closePath();
context.fill();
}
/*
返回此圆的半径。
@返回此圆的半径。
*/
node.getRadius=函数(){
返回半径;
};
/*
设置此圆的半径。
@param theRadius这个圆的新半径。
*/
node.setRadius=函数(theRadius){
半径=半径;
};
/*
返回此圆的颜色。
@返回此圆的颜色。
*/
node.getColor=函数(){
返回颜色;
};
/*
设置此圆的颜色。
@param颜色此圆的新颜色。
*/
node.setColor=函数(颜色){
颜色=颜色;
};
//返回节点
返回节点;
};
该代码的工作原理与Shape.Circle用户的工作原理完全相同,但感觉像是用胶带粘在一起的。有人能对此提供一些见解吗?我相信99%的情况都是这样。 这段代码看起来像Java。它不使用原型继承。它会在每次对象创建时创建新方法 尤其是:
抛出异常。methodNotOverrided
。就是那种我带我的程序员去会议室的JS代码
几个月前,我写了一篇关于JavaScript过度抽象的文章:
这个问题提供了更多关于这个主题的见解:这将是一个观点驱动的问题。但我会把我的0.02美元投进去 tl/dr:不要太担心这个问题。JavaScript非常灵活,可以支持很多操作方式。有条理就是有条理。你可能很好 更详细的答覆: 1) 在有意义的地方使用类:问题域适合类/类层次结构建模的地方。这是一个问题域,在这个问题域中,您拥有各种形状对象,这些对象具有从基类继承的通用方法和其他多态方法。。。好吧,这(字面上)是一个教科书上的例子,其中类层次结构是显而易见的,可能是有用的,以类为中心的代码在那里是有意义的,并且没有任何问题 2) 您甚至不必使用闭包/模块模式/任何东西。在编写类时,大多数情况下,使用JavaScript中可用的本机类ish功能并没有什么错——只需定义构造函数,然后为构造函数定义原型对象并将方法放在其上即可。当您想要从该类继承时,将子类的原型对象指定给从中派生的类的实例 (例如:
Drawing.Node = (function() {
var Node = function (context,position) {
this.context = context;
this.position = position;
}
Node.prototype = {
draw: function() { throw Exception.MethodNotOverridden; },
getContext: function() { return this.context; },
getPosition: function() { return this.position; },
setPosition: function(newPosition) { this.position = newPosition; }
};
return Node;
})();
Shape.Circle = (function () {
var Circle = // Circle constructor function
Circle.prototype = new Draw.Node;
Circle.prototype.overriddenmethod1 = function () {
}
Circle.prototype.overriddenmethod2 = function () {
}
return Circle;
})()
)
私有成员/方法如何?这是一种观点,但大多数时候,我认为隐私作为一种运行时强制机制被过度使用,甚至被滥用。开发商有很多事情要做;他们可能宁愿不关注任何给定抽象的内部,除非它泄漏了有害的东西。如果您的类不会引起问题,不会抛出/返回有用的错误,不会提供真正有用的方法,也不会记录得很好,那么您就不需要任何隐私了
Drawing.Node = function (context,position) {
this.context = context;
this.position = position;
}
Drawing.Node.prototype = {
draw: function() { throw Exception.MethodNotOverridden; },
getContext: function() { return this.context; },
getPosition: function() { return this.position; },
setPosition: function(newPosition) { this.position = newPosition; }
};