使用原型在JavaScript中封装

时间:2014-06-30 15:13:49

标签: javascript class prototype sandbox encapsulation

可能有很多人试图在JavaScript中实现封装。我知道的两种方法是:

我想更常见:

var myClass(){
  var prv //and all private stuff here
  //and we don't use protoype, everything is created inside scope
  return {publicFunc:sth};
}

和第二个:

var myClass2(){
  var prv={private stuff here}
  Object.defineProperty(this,'prv',{value:prv})
  return {publicFunc:this.someFunc.bind(this)};
}
myClass2.prototype={
  get prv(){throw 'class must be created using new keyword'},
  someFunc:function(){
    console.log(this.prv);
  }
}
Object.freeze(myClass)
Object.freeze(myClass.prototype)

所以,第二种选择对我来说更方便(特别是在我的情况下,因为它在视觉上将结构与工作流分开),问题是 - 在这种情况下是否有任何严重的缺点/泄漏?我知道它允许外部代码通过

访问someFunc的参数
myClass.protoype.someFunc.arguments

但仅限于执行粗略的回调(在调用者链内同步)。使用setTimeout(cb,0)调用它们可以打破链并禁止获取参数以及同步返回值。至少据我所知。

我错过了什么吗?这很重要,因为外部的,不受信任的用户提供的代码将使用代码。

3 个答案:

答案 0 :(得分:4)

我喜欢将我的原型包装在一个返回对象的模块中,这样你就可以将模块的范围用于任何私有变量,保护你的对象的消费者不会意外地搞乱你的私有属性。

var MyObject = (function (dependency) {

  // private (static) variables
  var priv1, priv2;

  // constructor
  var module = function () {
    // ...
  };

  // public interfaces
  module.prototype.publicInterface1 = function () {
  };

  module.prototype.publicInterface2 = function () {
  };

  // return the object definition
  return module;

})(dependency);

然后在其他文件中,您可以像平常一样使用它:

obj = new MyObject();

你的对象的任何“保护”对于JavaScript imo来说都有点过分。如果有人想扩展你的对象,那么他们可能知道他们正在做什么,你应该让他们!

正如redbmk指出,如果您需要私有实例变量,您可以使用带有该对象的唯一标识符的地图作为密钥。

答案 1 :(得分:1)

  

所以,第二个选项对我来说更方便(特别是在我的情况下,因为它在视觉上将构造与工作流分开),问题是 - 在这种情况下是否有任何严重的缺点/泄漏?

嗯,它并没有真正使用原型。这里没有理由“封装”任何东西,因为原型方法只能使用公共属性 - 就像你的不受信任的代码可以访问它们一样。一个简单的

function myClass2(){
  var prv = // private stuff here
  Object.defineProperty(this, 'prv', {value:prv})
  // optionally bind the publicFunc if you need to
}
myClass2.prototype.publicFunc = function(){
  console.log(this.prv);
};

应该足够了。或者您使用工厂模式,没有任何原型:

function myClass2(){
  var prv = // private stuff here
  return {
    prv: prv,
    publicFunc: function(){
      console.log(this.prv); // or even just `prv`?
    }
  };
}
  

我知道它允许外部代码访问someFunc的参数   myClass.protoype.someFunc.arguments

只需使用严格模式,就不允许使用此“功能”。

  

这很重要,因为外部的,不受信任的用户提供的代码将使用代码。

如果代码在同一环境中运行,他们将始终获取您的秘密。总是。您可能想要尝试WebWorkers,但请注意它们仍然是CORS特权。

答案 2 :(得分:0)

使用不能正确支持私人,受保护和公共类成员的语言强制执行封装,我说" Meh。"

我喜欢Foo.prototype = { ... };语法的清晰度。公开方法还允许您对"类"中的所有方法进行单元测试。最重要的是,我只是从安全的角度来看,不相信JavaScript。始终在保护系统的服务器上采取安全措施。

轻松编程和测试"和#34;清洁代码。"使编写和维护变得容易,因此无论您感觉更容易编写和维护都是答案。