从 java 到 javascript:对象模型
我正在尝试将我用java编写的应用程序移植到javascript(实际上使用coffeescript)。
现在,我感到迷失了..您建议做什么来创建类属性?我应该使用 getter/setter 吗?我不喜欢这样做:
myObj.prop = "hello"
因为我可以使用不存在的属性,并且很容易拼错某些东西..
我怎样才能让javascript更像java,具有私有、公共最终属性等..?有什么建议吗?
I'm trying to port an application I wrote in java to javascript (actually using coffeescript).
Now, I'm feeling lost.. what do you suggest to do to create class properties? Should I use getter/setters? I don't like to do this:
myObj.prop = "hello"
because I could use non existing properties, and it would be easy to mispell something..
How can I get javascript to be a bit more like java, with private, public final properties etc..? Any suggestion?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
如果您只是将 Java 代码翻译为 JavaScript,那么您将不断地与 JavaScript 的对象模型作斗争,该模型是基于原型的,而不是基于类的。对象上没有私有属性,也没有最终属性,除非您使用 ES5 兼容 引擎(您没有没有提到你的目标运行时环境是什么;浏览器不使用 ES5 兼容,这还需要几年的时间),实际上根本没有类。
相反,我建议您彻底了解面向对象在 JavaScript 中的实际工作原理,然后构建完全采用 JavaScript 如何实现的应用程序。这并非微不足道,但却是有益的。
一些可能有用的文章。我从闭包开始,因为真正理解闭包对于编写 JavaScript 来说是绝对必要的,而且大多数“私有成员”解决方案都依赖于闭包。然后我参考了 Douglas Crockford 的几篇文章。如果你打算使用 JavaScript 工作,Crockford 是必读的书,即使你最终不同意他的一些结论。然后我指出了几篇专门讨论类类事情的文章。
此
- 我解决您的一些具体问题:
我不喜欢,我更喜欢使用 < a href="http://en.wikipedia.org/wiki/Test-driven_development" rel="noreferrer">TDD 确保如果我确实有拼写错误,它会在测试中被发现。 (一个好的代码完成编辑器在这里也会很有帮助,尽管真正优秀的 JavaScript 代码完成编辑器在地面上很薄弱。)但是你是对的,Java 意义上的 getter 和 setter(方法)例如
getFoo
和setFoo
)会让在您创建/访问未事先定义的属性时变得更加明显(例如,由于拼写错误)导致运行时错误,调用不存在的函数。 (我说“在 Java 意义上”是因为 ES5 的 JavaScript 有 一种不同类型的“getters”和“ setters” 是透明的,对此没有帮助。)所以这是使用它们的一个论据。如果您这样做,您可以考虑使用 Google 的Closure 编译器来进行发布版本,因为它将内联他们。我已经链接了Crockford关于私有成员的文章,以及我自己的文章,其中列出了其他方法。 Crockford 模型的基本解释是:您在通过调用构造函数创建的上下文中使用变量,以及在该上下文中创建的可以访问该变量的函数(闭包),而不是对象属性
: >bar 不是对象属性,但在上下文中定义的函数对其具有持久引用。如果您的
Foo
对象数量较少,那么这完全没问题。如果您将拥有数千个Foo
对象,您可能需要重新考虑,因为每个Foo
对象都有自己的两个函数(Foo_getBar
和Foo_setBar
的Function
实例确实不同。你会经常看到上面这样写:
是的,它更简短,但现在函数没有名称,并给你的函数命名帮助您的工具为您提供帮助。
您可以定义一个没有 setter 的 Java 风格的 getter。或者,如果您的目标环境将兼容 ES5(同样,浏览器尚未兼容,还需要几年时间),您可以使用新的
Object.defineProperty
功能允许您设置无法写入的属性。但我的主要观点是拥抱你工作的语言和环境。学好它,您会发现应用的模式与 Java 中不同。两者都是很棒的语言(我经常使用它们),但它们的工作方式不同并导致不同的解决方案。
If you just translate your Java code into JavaScript, you're going to be constantly fighting JavaScript's object model, which is prototype-based, not class-based. There are no private properties on objects, no final properties unless you're using an ES5-compatible engine (you haven't mentioned what your target runtime environment is; browsers aren't use ES5-compatible, it'll be another couple of years), no classes at all in fact.
Instead, I recommend you thoroughly brief yourself on how object orientation actually works in JavaScript, and then build your application fully embracing how JavaScript does it. This is non-trivial, but rewarding.
Some articles that may be of use. I start with closures because really understanding closures is absolutely essential to writing JavaScript, and most "private member" solutions rely on closures. Then I refer to a couple of articles by Douglas Crockford. Crockford is required reading if you're going to work in JavaScript, even if you end up disagreeing with some of his conclusions. Then I point to a couple of articles specifically addressing doing class-like things.
this
- MeAddressing some of your specific questions:
I don't, I prefer using TDD to ensure that if I do have a typo, it gets revealed in testing. (A good code-completing editor will also be helpful here, though really good JavaScript code-completing editors are thin on the ground.) But you're right that getters and setters in the Java sense (methods like
getFoo
andsetFoo
) would make it more obvious when you're creating/accessing a property that you haven't defined in advance (e.g., through a typo) by causing a runtime error, calling a function that doesn't exist. (I say "in the Java sense" because JavaScript as of ES5 has a different kind of "getters" and "setters" that are transparent and wouldn't help with that.) So that's an argument for using them. If you do, you might look at using Google's Closure compiler for release builds, as it will inline them.I've linked Crockford's article on private members, and my own which lists other ways. The very basic explanation of the Crockford model is: You use a variable in the context created by the call to your constructor function and a function created within that context (a closure) that has access to it, rather than an object property:
bar
is not an object property, but the functions defined in the context with it have an enduring reference to it. This is totally fine if you're going to have a smallish number ofFoo
objects. If you're going to have thousands ofFoo
objects you might want to reconsider, because each and everyFoo
object has its own two functions (really genuinely differentFunction
instances) forFoo_getBar
andFoo_setBar
.You'll frequently see the above written like this:
Yes, it's briefer, but now the functions don't have names, and giving your functions names helps your tools help you.
You can define a Java-style getter with no setter. Or if your target environment will be ES5-compliant (again, browsers aren't yet, it'll be another couple of years), you could use the new
Object.defineProperty
feature that allows you to set properties that cannot be written to.But my main point is to embrace the language and environment in which you're working. Learn it well, and you'll find that different patterns apply than in Java. Both are great languages (I use them both a lot), but they work differently and lead to different solutions.
您可以使用 模块模式 来创建私有属性和公共访问器作为另一种选择。
You can use module pattern to make private properties and public accessors as one more option.
这并不能直接回答你的问题,但我会放弃尝试让 JavaScript 应用程序像 Java 一样的想法。它们确实是不同的语言(尽管语法和名称有一些相似之处)。一般来说,在移植某些东西时采用目标语言的习惯用法是有意义的。
This doesn't directly answer your question, but I would abandon the idea of trying to make the JavaScript app like Java. They really are different languages (despite some similarities in syntax and in their name). As a general statement, it makes sense to adopt the idioms of the target language when porting something.
目前有很多选择供你选择,你可以查看dojo库。在dojo中,您可以像java编程一样编写代码
Javascript 没有像 Java 那样的类系统,dojo 提供 dojo.declare 来定义模拟它的功能。检查此页面。有字段变量、构造方法、从其他类扩展。
Currently there are many choices for you , you can check dojo library. In dojo, you can code mostly like java programming
Javascript doesn’t have a Class system like Java,dojo provide dojo.declare to define a functionality to simulate this. Check this page . There are field variable, constructor method, extend from other class.
JavaScript 有一个特性,构造函数可以返回任何对象(不一定是 this)。因此,您的构造函数可以只返回一个代理对象,该对象仅允许访问类的公共方法。使用此方法,您可以创建真正受保护的成员,就像在 Java 中一样(通过继承、super() 调用等)。
我创建了一个小库来简化此方法:http://idya.github.com/oolib/
JavaScript has a feature that constructor functions may return any object (not necesserily this). So, your constructor function could just return a proxy object, that allows access only to the public methods of your class. Using this method you can create real protected member, just like in Java (with inheritance, super() call, etc.)
I created a little library to streamline this method: http://idya.github.com/oolib/
道场是一种选择。我个人更喜欢 Prototype。它还具有一个框架和 API,用于创建类并以更“java 风格”的方式使用继承。请参阅 API 中的
Class.create
方法。我已经在我开发的多个网络应用程序上使用了它。Dojo is one option. I personally prefer Prototype. It also has a framework and API for creating classes and using inheritance in a more "java-ish" way. See the
Class.create
method in the API. I've used it on multiple webapps I've worked on.我主要同意 @Willie Wheeler 的观点,即你不应该太努力地让你的应用程序像 Java 一样 - 有一些方法可以使用 JavaScript 来创建私有成员等内容 - Douglas Crockford 和其他人写过关于此类事情的文章。
I mainly agree with @Willie Wheeler that you shouldn't try too hard to make your app like Java - there are ways of using JavaScript to create things like private members etc - Douglas Crockford and others have written about this kind of thing.
我是 PragProg 的 CoffeeScript 书 的作者。现在,我使用 CoffeeScript 作为我的主要语言;在学习 CoffeeScript 的过程中,我熟练掌握了 JavaScript。但在此之前,我最好的语言是 Java。
所以我知道你正在经历什么。 Java 拥有一套非常强大的最佳实践,可以让您清楚地了解什么是好的代码:干净的封装、细粒度的异常、彻底的 JavaDoc 以及无处不在的 GOF 设计模式。当你切换到 JavaScript 时,这些问题就消失了。几乎没有什么“最佳实践”,更多的是一种模糊的“这很优雅”的感觉。然后,当您开始看到错误时,会感到非常沮丧——没有编译时错误,而且运行时错误少得多、不太精确。就像没有网玩一样。虽然 CoffeeScript 添加了一些 Java 程序员可能看起来很熟悉的语法糖(尤其是类),但它确实是一个飞跃。
我的建议是:学习编写优秀的 CoffeeScript/JavaScript 代码。试图让它看起来像 Java 是一条通往疯狂的道路(相信我,很多人都尝试过;请参阅:Google 发布的任何 JS 代码)。好的JS代码是比较简约的。不要使用
get
/set
方法;谨慎使用异常;并且不要对所有事情都使用类或设计模式。 JS 归根结底是一种比 Java 更具表现力的语言,CoffeeScript 更是如此。一旦你习惯了随之而来的危险感,你就会喜欢它。需要注意的是:总的来说,JavaScript 工程师在测试方面表现很糟糕。市面上有很多优秀的 JS 测试框架,但健壮的测试比 Java 世界要少得多。因此,在这方面,JavaScript 开发人员可以向 Java 开发人员学习一些东西。使用 TDD 也是一种很好的方法,可以缓解您对犯错误是多么容易的担忧,否则只有应用程序的某些特定部分运行时才会发现这些错误。
I'm the author of the CoffeeScript book from PragProg. Right now, I use CoffeeScript as my primary language; I got fluent in JavaScript in the course of learning CoffeeScript. But before that, my best language was Java.
So I know what you're going through. Java has a very strong set of best practices that give you a clear idea of what good code is: clean encapsulation, fine-grained exceptions, thorough JavaDocs, and GOF design patterns all over the place. When you switch to JavaScript, that goes right out the window. There are few "best practices," and more of a vague sense of "this is elegant." Then when you start seeing bugs, it's incredibly frustrating—there are no compile-time errors, and far fewer, less precise runtime errors. It's like playing without a net. And while CoffeeScript adds some syntactic sugar that might look familiar to Java coders (notably classes), it's really no less of a leap.
Here's my advice: Learn to write good CoffeeScript/JavaScript code. Trying to make it look like Java is the path to madness (and believe me, many have tried; see: just about any JS code released by Google). Good JS code is more minimalistic. Don't use
get
/set
methods; use exceptions sparingly; and don't use classes or design patterns for everything. JS is ultimately a more expressive language than Java is, and CoffeeScript even moreso. Once you get used to the feeling of danger that comes with it, you'll like it.One note: JavaScripters are, by and large, terrible when it comes to testing. There are plenty of good JS testing frameworks out there, but robust testing is much rarer than in the Java world. So in that regard, there's something JavaScripters can learn from Java coders. Using TDD would also be a great way of easing your concerns about how easy it is to make errors that, otherwise, wouldn't get caught until some particular part of your application runs.