使用类似于C ++ class-private的隐私和原型(模板)创建对象

时间:2011-12-24 19:23:15

标签: javascript c++

**编辑 - 这在答案中没有明确说明......但是你不能拥有“模板化(即不为每个实例复制)”的私人成员而没有自动执行功能。您将使用处理器时间和代码复杂性来支付隐私

与C ++私有类成员一样。

我一直在努力确定创建类的defacto“hack”是什么似乎有超过10种人们定义类的方式。

我正在寻找的类的类型提供隐私和模块化以及模板机制。 Javascript有原型来创建这个模板机制。但是,我目前在下面使用的解决方案没有私人成员。

如果没有,我不得不问这个问题,如果我将所有的javascript移动到这个类类型的话,成本是多少...其中每个都是自动执行功能?现在,当我的代码加载时,所有代码都必须在可以使用之前运行。

这个成本是更好的编程实践的权衡。现在我有适当的隐私课程。

成本值得吗?额外的运行时间值得隐私吗?

以下是一些类似的问题:

现行方法 - 缺乏隐私......散开......没有包含在parantheses中

var Message = function( div ) 
{
    this.div = document.getElementById( div ); 
};

Message.prototype.messages = 
{ 
    name:       'Please enter a valid name',
    email:      'Please enter a valid email',
    pass:       'Please enter passoword, 6-40 characters',
    url:        'Pleae enter a valid url',
    title:      'Pleae enter a valid title',
    tweet:      'Please enter a valid tweet',
    empty:      'Please complete all fields',
    same:       'Please make emails equal',
    taken:      'Sorry, that email is taken',
    validate:   'Please contact <a class="d" href="mailto:support@host.com">support</a> to reset your password'
};

Message.prototype.display = function( type ) 
{
    Control.sendInner( this.div, this.messages[type] );
};

4 个答案:

答案 0 :(得分:4)

  

Javascript有创建这种模板机制的原型。但是,我目前在下面使用的解决方案没有私人成员。

我知道使用原型和私有状态的唯一机制是WeakMaps。

这基本上涉及在原型范围内具有本地WeakMap

免责声明: WeakMaps are ES6 ,我相信目前只有firefox 6 has an implementation,但他们可以be shimmed

var Message = (function() {
    var map = new WeakMap();

    var Message = function(div) {
        var privates = {};
        map.set(this, privates);
        privates.div = document.getElementById(div);
    };

    Message.prototype.messages = {
        name: 'Please enter a valid name',
        email: 'Please enter a valid email',
        pass: 'Please enter passoword, 6-40 characters',
        url: 'Pleae enter a valid url',
        title: 'Pleae enter a valid title',
        tweet: 'Please enter a valid tweet',
        empty: 'Please complete all fields',
        same: 'Please make emails equal',
        taken: 'Sorry, that email is taken',
        validate: 'Please contact <a class="d" href="mailto:support@host.com">support</a> to reset your password'
    };

    Message.prototype.display = function(type) {
        var privates = map.get(this);
        Control.sendInner(privates.div, this.messages[type]);
    };

    return Message;
}());

请注意,WeakMaps是ES6,并且从弱映射而不是this获取对象会产生大量计算开销。

我有一篇关于模仿WeakMaps的文章 - Prototypes and privates state

使用文章中提到的klass实用程序代码如下:

var Message = klass(function(privates) {
    return {
        constructor: function(div) {
            privates(this).div = document.getElementById(div);
        },
        messages: {
            name: 'Please enter a valid name',
            email: 'Please enter a valid email',
            pass: 'Please enter passoword, 6-40 characters',
            url: 'Pleae enter a valid url',
            title: 'Pleae enter a valid title',
            tweet: 'Please enter a valid tweet',
            empty: 'Please complete all fields',
            same: 'Please make emails equal',
            taken: 'Sorry, that email is taken',
            validate: 'Please contact <a class="d" href="mailto:support@host.com">support</a> to reset your password'
        },
        display = function(type) {
            Control.sendInner(privates(this).div, this.messages[type]);
        }
    };
});

再次使用privates(this).x代替this.x会产生两个函数调用的计算开销。这不应该被忽视。

另请注意,使用weakmaps与使用闭包相比,内存开销要少得多,因为你仍然使用原型进行函数,只使用弱映射进行状态。

  

成本值得吗?额外的运行时间值得隐私吗?

就个人而言,我说“隐私”的运行时间惩罚是需要进行基准测试的。计算开销很小,内存使用开销也很小。

答案 1 :(得分:0)

所以,我使用的形式是:

var Message = function (div) {
    this.div = document.getElementById(div);
    // messages will be 'private'
    var messages = { 'name' : 'Please enter ...' }; // You get the picture here

    this.display = function (type) {
        Control.sendInner(this.div, messages);
    }
}

您可以在Object Scope标题下阅读有关私有,静态和公共变量in this post的更多信息。

更新:您还可以使用Strict Mode并设置不可写变量或仅限getter值。尽管如此,您可能希望这不受支持,并且可能会使您在编写代码方面更加严格。

答案 2 :(得分:0)

在你的构造函数中,你在中声明的任何变量该函数实际上都是私有的 - 它的范围仅限于该实例,即:

var Message = function( div ) 
{
    var private = "hello, world!";
    this.div = document.getElementById( div ); 
};

但是,这些变量所以私有,无法从您随后添加到原型的函数中访问它们。

访问它们的唯一方法是通过所谓的&#34;特权方法&#34;,即在对象内创建this 属性的方法。

答案 3 :(得分:0)

除非使用变量的范围规则,否则我认为JavaScript中不存在任何隐私。但这并不总是意味着立即调用的函数表达式。您可以使用构造函数范围的变量与构造函数指定的方法相结合,如下所示:

function YourConstructor() {
    var private1 = 0,
        private2 = 'spock';

    this.count = function () { return private1++; }    
    this.chiefOfficer = function (name) { 
       if(name) private2 = name;
       return private2; 
    }
}

即使您在定义YourConstructor之前执行代码,也会发生前向声明魔术并且一切正常(注意:发布的其他一些解决方案使用{{1} } idiom - 在需要前向声明的情况下,这些将不起作用

这有一个问题:每次调用构造函数时,都要定义构造函数指定的方法(而不是一次分配给原型)。在您创建大量这些对象的情况下,可能会有性能/内存命中。

关于隐私的一句话:我邀请您考虑一下这样的观点,即大多数时候,通过运行时强制机制对隐私的需求被高估了。

为什么呢?开发人员有很多事情要做;很可能,他们可能宁愿不 注意任何给定抽象的内部,除非它泄漏了一些有害的东西。

不会导致问题的类,抛出/返回有用的错误,提供真正有用的方法,你可以调用它来完成任务(对很多getter和setter!),并且记录得很好......这些这类课程可能不需要任何形式的隐私执行机制,因为每个人都会对你的课程拯救他们的工作感到满意,他们永远不会在里面找到他们。

对于不符合该标准的课程,缺乏隐私执法机制可能不是真正的问题。

有一个例外:有时候(特别是在可以通过网络浏览的网页上),你有来自不信任来源的代码与你的混合。在一种非常动态的语言(如JavaScript)中,您可能希望在外部代码无法访问的地方隔离/隐藏某些功能。但是,如果您不担心这一点,您可能希望通过良好的设计和文档在社交上花费更多时间鼓励实施隐藏/隐私,而不必担心技术执行。