【问题标题】:Better way to access private members in Javascript在 Javascript 中访问私有成员的更好方法
【发布时间】:2009-06-25 03:13:43
【问题描述】:

在阅读了一些关于 Javascript 的 prototypical inheritance model 之后,我改变了构建类的风格

var Some_Class = function() {
    this.public_method = function() {
    };
    (function() {
        // constructor
    }).call(this)
}

var Some_Class = function() {
    (function() {
        // constructor
    }).call(this)
}
Some_Class.prototype.public_method = function() {
};

虽然我明白这是一个很好的做法,但我不再被允许从公共方法访问私有方法

var Some_Class = function() {
    var private_member = 'whatever';

    (function() {
        // constructor
    }).call(this)
}
Some_Class.prototype.public_method = function() {
    return private_member; // not possible
};

看了一篇文章here(闭包创建的构造函数),然后我就得出了这个

var Some_Class = function() {
    var private_member = 'whatever',

    private_method = function(_some_value) {
        // private method implementation
    };

    if(!arguments.callee.prototype.public_method) {
        arguments.callee.prototype.public_method = function() {
            private_method.call(this, private_method);
        };
    }

    (function() {
        // constructor
    }).call(this)
}

但是,这样做的缺点是什么?!或者如果我想在公共方法中访问private member,有没有更好的方法?

【问题讨论】:

    标签: javascript prototype


    【解决方案1】:

    我的回答是不回答:JavaScript 中没有内置的private 访问权限,但这没关系,因为YAGNI。以下是我在代码中创建 private 成员的方法:

    function Some_Class() {
        this._private_member = 'whatever';
    }
    
    Some_Class.prototype._private_method = function() {
    };
    

    这就够了。当private 的唯一真正目的是保护自己免受……自己的伤害时,跳槽真的不值得。

    (我说这个我自己花了很多时间玩各种闭包和原型设计,就像你一样,最后说“去他妈的,这不值得”。)

    【讨论】:

    • 我同意。以不支持的语言强制使用虚假的私人访问通常意味着你做得很好。
    • @Triptych - 虽然我普遍同意,如果你必须与设计良好的语言作斗争才能做你想做的事,那么你真的应该重新考虑你的设计。但是,在这种情况下,通过函数范围变量和闭包模拟私有访问被许多成熟且经验丰富的 javascript 程序员认可为一种自然的 javascript 习惯用法。
    • +1 一个副作用是所有古怪的闭包方案往往会破坏许多 IDE 代码辅助
    【解决方案2】:

    使用函数作用域变量和闭包来模拟私有变量/函数是 javascript 社区中公认的惯用语。如果该变量确实是私有的,我认为这种方法没有缺点(尽管有人声称某些浏览器/主机上的高性能代码必须注意创建了多少闭包)。

    在您的示例中,private_method(及其环境)在所有对象之间共享-因为您的 public_method 闭包仅在第一次构造对象时创建(并绑定到设置创建对象的内部原型链的构造函数的原型属性) - 所以使用的 private_method 只是第一次创建的那个。

    下面是一些示例代码,有助于说明发生了什么:

    变量全局 = 1; var Some_Class = function() { var private_method = '随便'; var now = ++全局; print("现在外面:" + now ); 私有方法 = 函数(_some_value){ // 私有方法实现 print("现在内部:" + now); }; if(!arguments.callee.prototype.public_method) { arguments.callee.prototype.public_method = function() { private_method.call(this, private_method); }; } (功能() { // 构造函数 }).call(这个) } 新的 Some_Class().public_method(); // 现在外部:2,内部现在:2 新的 Some_Class().public_method(); // 现在外部:3,内部现在:2 新的 Some_Class().public_method(); // 现在外部:4,内部现在:2

    你确定这是你想要的吗?

    如果您的 private_method 不需要引用封闭对象的状态,那么我认为按照您的方式做事几乎没有什么好处。

    我通常做的(如果我必须使用'new'来创建我的对象)如下:

    函数 MyClass() { var private_var = 1; 函数 private_func() { } this.public_func = 函数() { // 做点什么 私人函数(); } this.public_var = 10; } var myObj = new MyClass();

    这种方法的缺点是每次通过“new”构造对象时,都会重新创建所有闭包。但除非我的分析器告诉我这个设计选择需要优化,否则我更喜欢它的简单明了。

    我也没有看到您的代码执行以下操作的好处:

    (function() { }).call(this); // 调用构造函数

    为什么要在构造函数中创建单独的范围?

    【讨论】:

    • 感谢您为第二个问题澄清这一点...我想这可能是因为我对对象模型还不是很熟悉,并且想让我的代码类似于 php 中的 OOP 代码/java/其他面向对象编程语言
    【解决方案3】:

    如果您还没有这样做,请查看JavaScript Module Pattern,它允许您从公共函数等访问私有方法和变量。

    【讨论】:

    • :D 我以前读过它,只是出于某种原因我不太喜欢单例模式并想找到另一种方法......
    【解决方案4】:

    呼应 John Kugelman:在 javascript 中创建私有成员是不可能的。忍受它。即使您创建这样的外壳:

    function SomeClass() {
    
       var _private = 0;
       this.public_acessor = function() {return _private};
    }
    

    任何用户仍然可以写:

    SomeClass._not_private_anymore = 1;
    SomeClass.public_acessor = function () {return this._not_private_anymore}; 
    

    最后,您不能相信任何公共成员与您声明的相同。如果有人想要破解你的代码,他会的!其他用户不会仅仅因为它有用就破坏您的代码。

    【讨论】:

      【解决方案5】:

      适用于原型,而不仅仅是单例。问题是,当需要子类化时,我的子类无法访问私有数据

      【讨论】:

      • 即使是 Java 中的子类也无法访问其 super 的私有信息。
      猜你喜欢
      • 2014-08-21
      • 2011-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多