JavaScript 是一种基于原型(prototype)的语言,但它能够模仿基于类的面向对象语言的某些功能。例如,JavaScript 没有公共(public)成员和私有(private)成员的概念,但通过闭包的魔力,它仍然可以提供相同的功能。类似地,方法重载、接口(interface)、 namespace 和抽象类都可以以一种或另一种方式添加。
最近,由于我一直在使用 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, 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;
};
该代码的工作方式与 Shape.Circle 的用户应有的完全一样,但感觉就像是用 Duct Tape 结合在一起的。有人可以对此提供一些见解吗?
最佳答案
这将是一个意见驱动的问题。但我会投入我的 $.02。
tl/dr:不要太担心这个。 JavaScript 非常灵活,可以支持多种做事方式。井井有条就是井井有条。你可能没事。
更详细的回答:
1) 在有意义的地方使用类:问题域适合类/类层次结构建模的地方。一个问题领域,你有各种各样的形状对象,这些形状对象具有从基类和其他多态方法继承的通用方法......好吧,这是(字面上)类层次结构明显且可能有用的案例的教科书示例,并且以类为中心的代码在那里是有意义的,并且没有任何问题。
2) 您甚至不必使用闭包/模块模式/任何东西。当您编写类时,大多数时候使用 JavaScript 中可用的 native 类功能并没有错——只需定义构造函数,然后为构造函数定义原型(prototype)对象并将您的方法放在上面。当您想从该类继承时,将子类的原型(prototype)对象分配给您从中派生的类的实例。
(例如:
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;
})()
)
私有(private)成员/方法呢?这是一种观点,但大多数时候,我认为隐私作为一种运行时强制机制被过度使用甚至滥用。开发人员有很多工作要做;他们可能宁愿不注意任何给定抽象的内部结构,除非它泄漏了有害的东西。如果你的类不会引起问题,抛出/返回有用的错误,提供真正有用的方法,并且有足够的文档记录,你就不需要任何类型的隐私强制机制,因为每个人都会对你的类所节省的工作感到非常满意他们永远不会向里面窥视。如果您的类(class)不符合该标准,那么,缺乏隐私执行机制并不是您的真正问题。
有一个异常(exception),那就是当您在一个页面/应用程序中混合使用来自不同(且通常不受信任)来源的 JavaScript 代码时。此时,出于安全原因,您有时必须仔细考虑在您的代码和您的代码单独访问的给定范围内隔离一些关键功能/方法。
编辑/附录
在回答关于为什么我有那些立即评估的函数的问题时,考虑这种编写 Drawing.Node 定义的替代方法:
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; }
};
这与上面的代码完全相同。恕我直言,它也是完全可以接受的,并且可能更清晰一些,不那么棘手。
另一方面,我发现将所有这些都放在立即执行的匿名函数的范围内给我至少两个优势:
如果我确实决定我需要定义任何私有(private)方法或以其他方式进行一些仅与该特定类定义相关的设置工作,它会为我提供一个很好的私有(private)范围来工作。
如果我决定需要将 Node 在命名空间对象层次结构中的位置移动到其他地方,如果与其定义相关的所有内容都集中在一个方便的位置,那会比较方便。
有时这些优势很小。有时它们更引人注目。 YMMV。
关于javascript - 将基于类的设计应用于 JavaScript 程序是否是一种不好的做法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4487754/
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R