封装与封装类相比?

时间:2012-01-04 15:51:51

标签: javascript class closures

我是JS的新手(来自C ++ /等),我刚刚想到闭包似乎是一种比类更简单,更方便的处理封装的方法。这段代码似乎提供了一种处理封装的简单方法:

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);

如果你只是想要一个类来处理封装(在C ++中,我发现这是大部分时间),有没有什么好的理由使用JS类而不是闭包?在我看来,上面的代码比JS类更直观,更紧凑。没有构造函数,原型或过度使用'this'。您还可以获得必须明确声明本地字段的好处,而不是希望您不在构造函数中创建任何拼写错误。

修改

好的,我只是澄清一下。似乎'class'这个词得到了一些支持。无论如何,对我而言,“类”是类型概念的延伸,而JS在这方面没有资格,但我可以用我的书(Flanagan)花费50页调用类来做各种类的事情。排序。

无论如何,真正的问题是:我在我的第一个网络应用程序上使用jQuery选项卡。我昨天注意到这不起作用,因为我的JS代码没有为每个选项卡保留任何私有状态。当我在选项卡之间切换时,我的代码的动态/鼠标部分不再正常工作。

那么,将私有状态引入应用程序的最佳方法是什么?大多数代码都是安全的,但处理动态行为的所有内容都需要某种方式来封装每个选项卡的本地状态。使用C ++背景,我明显的答案是编写一个定义选项卡动态部分的类,并在每次创建选项卡时实例化一个新的“选项卡”对象。我发现难以理解的是JS伪类在这里是否真的有意义,或者我是否应该扩展上面的代码。

刚刚阅读Jonathan的模块模式链接,现在我觉得这可能就是答案。

感谢。

3 个答案:

答案 0 :(得分:15)

避免关闭的原因是开销。

你的get和set函数比属性慢20倍。你的闭包也有很大的内存开销,即O(N)和实例数。

另请注意,这些封装变量实际上没有任何好处,它们只是推断性能损失。

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);
  

昨天我注意到这不起作用,因为我的JS代码没有为每个标签保留任何私有状态。

你的问题不在于你没有私人状态,而是你正在使用全局状态。

简单的解决方案是每个标签有一个对象(如果你愿意,可以是“结构”)并在其中存储状态。

所以你要做的就是定义一个标签

var Tab = {
  constructor: function (...) {
    /* init state */
  },
  doTabStuff: function () { /* some method */ },
  ...
}

然后在需要时创建新标签

var tab = Object.create(Tab).constructor(...)

答案 1 :(得分:5)

为了封装功能,函数的好处是可以使用模块模式:

http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

模块模式提供了创建私有成员和方法的功能,没有像ease.js这样的大量开销:

http://easejs.org/

答案 2 :(得分:4)

这是一个老问题,但有一些答案缺失,所以我想我会加入这个。

首先,正如评论者喜欢指出的那样,javascripts中没有真正的类,我们只是用闭包来模仿它们。以下是javascript教程称之为“class:”

的内容
function Class1(){
    var privateState='blah';
    this.get=function(){
        return privateState;
    }
}
var myObj=new Class1();

重要的是,get方法只是一个闭包。所以,这与你的代码基本相同。因为闭包必须引用它们所在的环境(这是它们如何使用私有内部状态数据),所以它们比仅使用公共函数更昂贵。因此,如果您的静态方法不需要内部状态,则应使用Class1关键字将其添加到prototype

Class1.prototype.staticMethod=function(){...};

这样,静态方法可以通过原型链使用,而不会占用额外的内存和不必要的闭包。您也可以通过在AddProperty函数之外添加静态方法来实现此方法。

所以,最后,正式的javascript“class”和你的AddProperty函数之间的唯一区别是,当你实际使用类构造函数时,该类出现在对象的原型链中,而你的对象只是继承直接来自通用object原型。你当然可以编写使用这种区别的代码,但这可能是错误的代码。