javascript 用于封装的闭包与类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8729714/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Closures vs. classes for encapsulation?
提问by EML
I'm new to JS (from C++/etc), and it's just occurred to me that closures seem to be a simpler and more convenient way to handle encapsulation than classes. This code seems to give a simple way to handle encapsulation:
我是 JS 的新手(来自 C++/etc),我突然想到闭包似乎是一种比类更简单、更方便的封装处理方式。这段代码似乎提供了一种处理封装的简单方法:
function addProperty(o) {
var value;
o["get"] = function() { return value; }
o["set"] = function(v) { value = v; }
}
// create two independent objects which are instances of pseudo-class 'addProperty',
// which each have their own version of a set of local fields, and methods that
// operate on those fields:
var a = {};
addProperty(a);
var b = {};
addProperty(b);
If you just want a class to handle encapsulation (in C++, I find this is most of the time), is there any good reason to use a JS class instead of a closure? The code above seems to me to be more intuitive and compact than JS classes. No constructors, prototypes, or excessive use of 'this'. You also get the benefit that you must explicitly declare local fields, instead of hoping that you don't make any typos in your constructor.
如果你只是想要一个类来处理封装(在 C++ 中,我发现大部分时间都是这样),是否有充分的理由使用 JS 类而不是闭包?上面的代码在我看来比 JS 类更直观和紧凑。没有构造函数、原型或过度使用“this”。您还可以获得必须显式声明本地字段的好处,而不是希望您不要在构造函数中输入任何拼写错误。
EDIT
编辑
Ok, I'll just clarify. Seems like the 'class' word gets some backs up. A "class", to me anyway, is an extension of the type concept, and JS doesn't qualify on that front, but I can do various class-y things with what my book (Flanagan) spends 50 pages calling classes. Sort of.
好的,我会澄清一下。似乎“阶级”这个词得到了一些支持。无论如何,对我来说,“类”是类型概念的扩展,而 JS 在这方面不符合条件,但我可以用我的书 (Flanagan) 花费 50 页的时间来调用类的内容来做各种类的事情。有点。
Anyway, the real question is this: I'm using jQuery tabs on my first web app. I noticed yesterday that this doesn't work, because my JS code doesn't keep any private state for each tab. When I swap between tabs, the dynamic/mouse parts of my code no longer work properly.
无论如何,真正的问题是:我在我的第一个 Web 应用程序上使用 jQuery 选项卡。我昨天注意到这不起作用,因为我的 JS 代码没有为每个选项卡保留任何私有状态。当我在选项卡之间切换时,我的代码的动态/鼠标部分不再正常工作。
So, what's the best way to introduce private state into the app? Most of the code is safe, but everything that handles dynamic behaviour needs some way to encapsulate per-tab local state. With a C++ background, the obvious answer to me is to write a class that defines the dynamic parts of a tab, and to instantiate a new 'tab' object each time a tab is created. What I'm finding it difficult to get my head around is whether JS pseudo-classes actually make any sense here, or whether I should extend the code above.
那么,将私有状态引入应用程序的最佳方式是什么?大多数代码是安全的,但处理动态行为的所有内容都需要某种方式来封装每个选项卡的本地状态。有了 C++ 背景,对我来说显而易见的答案是编写一个定义选项卡动态部分的类,并在每次创建选项卡时实例化一个新的“选项卡”对象。我发现很难理解的是 JS 伪类在这里是否真的有意义,或者我是否应该扩展上面的代码。
Just read the module patterns link from Jonathan, and it now seems to me to be that that may be the answer.
只需阅读 Jonathan 的模块模式链接,现在在我看来这可能就是答案。
Thanks.
谢谢。
采纳答案by Raynos
The reasons to avoid closures is overhead.
避免关闭的原因是开销。
Your get and set functions are trivially 20x slower than properties. Your closures also have a large memory overhead that is O(N) with the number of instances.
你的 get 和 set 函数比属性慢 20 倍。您的闭包也有很大的内存开销,与实例数量的 O(N) 相同。
Also note that these encapsulated variables have zero real benefit, they just infer performance penalties.
还要注意,这些封装变量的实际收益为零,它们只是推断性能损失。
var AddProperty = {
constructor: function (v) { this._value = v; return this; },
get: function () { return this._value; },
set: function (v) { this._value = v; }
};
var a = Object.create(AddProperty).constructor(1);
var b = Object.create(AddProperty).constructor(2);
I noticed yesterday that this doesn't work, because my JS code doesn't keep any private state for each tab.
我昨天注意到这不起作用,因为我的 JS 代码没有为每个选项卡保留任何私有状态。
Your problem is not that you don't have private state, it's that you're using global state.
您的问题不是您没有私有状态,而是您使用的是全局状态。
The easy solution is to have an object per tab (or a "struct" if you prefer) and store state in it.
简单的解决方案是每个选项卡都有一个对象(或“结构”,如果您愿意)并在其中存储状态。
So all you have to do is define a tab
所以你所要做的就是定义一个选项卡
var Tab = {
constructor: function (...) {
/* init state */
},
doTabStuff: function () { /* some method */ },
...
}
And then create new tabs when you need them
然后在需要时创建新标签
var tab = Object.create(Tab).constructor(...)
回答by Matthew
This is an old question, but there are a few things the answers are missing so I figure I'd add to this.
这是一个老问题,但答案中缺少一些东西,所以我想我会补充一点。
First, as commenters love to point out, there aren't any real classes in javascripts, we just mimic them with closures. Here's what the javascript tutorials call a "class:"
首先,正如评论者喜欢指出的那样,javascripts 中没有任何真正的类,我们只是用闭包来模仿它们。这是 javascript 教程所说的“类”:
function Class1(){
var privateState='blah';
this.get=function(){
return privateState;
}
}
var myObj=new Class1();
Importantly, the get
method is just a closure. So, this is basically the same as your code. Because closures must reference the environment in which they were created (this is how they can use the private internal state data), they are more costly than just using a public function. So if you have a static method that doesn't require the internal state, you should add it to Class1
instead by using the prototype
key word:
重要的get
是,该方法只是一个闭包。所以,这与您的代码基本相同。因为闭包必须引用创建它们的环境(这是它们使用私有内部状态数据的方式),所以它们比仅使用公共函数的成本更高。因此,如果您有一个不需要内部状态的静态方法,则应Class1
使用prototype
关键字将其添加到:
Class1.prototype.staticMethod=function(){...};
This way, the static method can be used through the prototype chain without using up extra memory with unnecessary closures. You could also achieve this with your method by adding static methods outside of your AddProperty
function.
这样,静态方法可以通过原型链使用,而不会因不必要的闭包而占用额外的内存。您也可以通过在您的AddProperty
函数之外添加静态方法来使用您的方法来实现这一点。
So, in the end the only difference between a formal javascript "class" and your AddProperty
function is that when you actually use the class constructor, the class appears in the object's prototype chain, whereas your objects just inherit directly from the generic object
prototype. You could certainly write code that uses this distinction, but that would probably be bad code.
因此,最终正式的 javascript“类”和您的AddProperty
函数之间的唯一区别在于,当您实际使用类构造函数时,该类出现在对象的原型链中,而您的对象只是直接从通用object
原型继承。您当然可以编写使用这种区别的代码,但这可能是糟糕的代码。
回答by Jonathan Rich
The benefit of a function for the purposes of encapsulating functionality is that you can use the module pattern:
用于封装功能的函数的好处是您可以使用模块模式:
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
The module pattern provides the capability of creating private members and methods, without something with a lot of overhead like ease.js:
模块模式提供了创建私有成员和方法的能力,而没有像 easy.js 那样有很多开销的东西: