最近,由于我一直在编程JavaScript,我觉得我正试图把它变成一个基于类的语言,而不是按照它被使用的方式使用它.看来我试图强迫语言符合我习惯的习惯.
以下是我最近写的一些JavaScript代码.它的目的是抽象绘制HTML5 canvas元素所涉及的一些工作.
/* 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,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; };
该代码的工作原理与Shape.Circle的用户完全一样,但感觉就像它与Duct Tape一起使用.有人可以提供一些洞察力吗?
解决方法
tl / dr:不用担心太多了. JavaScript非常灵活,可以支持很多方法.组织良好组织良好.你可能很好
更详细的答案:
1)使用有意义的类:问题域适合class-ish / class层次结构建模.一个问题领域,你有各种各样的形状对象,这些对象具有从基类和其他多态方法继承的常用方法…好吧,这是一个例子,它是类层次结构明显可能有用的一个例子,而以类为重点的代码在这里是有意义的,没有任何错误.
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; })()
)
私人会员/方法怎么办?这是一个意见,但大多数时候,我认为作为运行时执行机制的隐私被滥用甚至被滥用.开发者有很多事要做;他们可能不会注意任何给定抽象的内部,除非它泄漏有毒的东西.如果您的课程不会引起问题,抛出/返回有用的错误,提供真正有用的方法,并且记录得足够好,您将不需要任何形式的隐私执行机制,因为每个人都将对您的课程节省的工作感到满意他们永远不会同行.如果您的课程不符合该标准,那么缺乏隐私执行机制就不是您的真正问题.
这是一个例外,当您有来自不同(通常不受信任)的源代码混合在页面/应用程序中的JavaScript代码时.在这一点上,出于安全考虑,您有时需要仔细考虑在给定范围内隔离代码和代码单独访问的一些重要功能/方法.
编辑/编
在回答关于为什么我有这些立即评估函数的问题时,请考虑编写Drawing.Node定义的另一种方法:
Drawing.Node = function (context,position) { this.context = context; this.position = position; } Drawing.Node.prototype = { draw: function() { throw Exception.MethodNotOverridden; },setPosition: function(newPosition) { this.position = newPosition; } };
这与上面的代码完全一样.也是,呃,完全可以接受,可能有点清晰,不太巧妙.
另一方面,我发现把所有这些都放在一个立即执行的匿名函数的范围内,至少有两个优点:
>如果我确定我需要定义任何私有方法,或者另外做一些仅与特定类定义相关的设置工作,它给我一个很好的私有作用域.
>如果我决定我需要将Node的位置移动到其他位置的命名空间对象层次结构中,那么如果与其定义相关的所有内容都被绑在一个方便的位置,那么它很方便.
有时这些优点很小.有时候他们有点更引人注目.因人而异.