4

我正在尝试用 JavaScript 编写完全自动化的单元测试,并且正在寻找一种方法来读取各种 JS 函数中的一些私有变量。我想我想起了一种将特权成员注入函数/对象的方法(并发现“在 JS 中没有私有这样的东西”),但我找不到任何说明如何的资源。

我正在尝试阅读的属性,.prototype但如果有办法,这里的人会比我自己找到的更快地知道在哪里指导我。

谢谢

更新

  1. 特权是指可从对象外部使用并有权读取“私有”变量(否则无法从外部读取的变量)的函数。有关 Crockford 的解释,请参阅http://javascript.crockford.com/private.html

  2. 我尝试注入的函数示例是o2,我需要验证的值x(这是一个简化的示例,实际代码进行了一些转换并将它们发送到我计划单独测试的其他函数)。

    var o2 = function() {
        var x = 'me';
    };
    

更新 2:感谢所有花时间回复的人。尽管我在其他 SA 问题中看到人们说“JS 中没有任何东西是私有的”,但我看到这里的压倒性反应是“私有的就是私有的”。我想这更像是修辞评论,而不是我希望的对我还不知道的潜在漏洞的某种洞察。

4

4 回答 4

3

正确回答你的问题

即使我们尽力帮助您,您的问题的正确答案也很简单:

……你不能

如果我们可以直接从闭包外部访问它们,那么闭包变量会有什么好处呢?

如果您有一个带有私有变量的对象,则它们将无法在函数闭包(即构造函数)之外访问。

var c = function() {
    var priv = "private";
    this.get = function() {
        return priv;
    };
}

var o = new c();
o.injected = function() {
    return priv; // ERROR!!!!!! priv doesn't exist in function scope
};

如果您将整个事物封装在一个函数闭包中当然是不同的事情,但是您不会有对象私有,而是函数闭包内部将在此闭包内的所有原型之间共享。

(function(){

    var intrn = "internal";

    // omit "var" to make it global
    c = function() {
        this.get = function() {
            return intrn;
        };
    };

    // omit "var" to make it global
    o = new c();
    o.injected = function() {
        return intrn; // WORKS
    };
})();

o.injected();

但这与对象私有不同...

于 2012-04-05T14:10:05.990 回答
1

知道我参加聚会已经很晚了,但是是的,这是可能的。虽然 AFAIK 它需要使用eval()和辅助方法:

function foo(){
    var a = 'a';
    this.addMethod = function(prop, val){
        this[prop] = eval('(' + val.toString() + ')');
    }
}
var bar = new foo();
bar.b = 'b';
var Fn = function(){return a + this.b}
bar.addMethod('getValue', Fn);
bar.getValue(); //yields 'ab'

在这种情况下,您可以eval()在闭包的上下文中重新定义函数。然而,使用eval()是危险的,特别是不要eval()任何用户输入,永远。但是,对于在测试套件/脚本中使用它应该没问题。

于 2014-06-19T15:56:48.343 回答
0

我建议您阅读Crockford 关于如何在 javascript 对象中实现特权和私有的论文。

如果通过特权,您的意思是在对象外部无法访问的方法,但可以被其他方法调用并且实际上是对象上的方法,那么实际上没有任何方法可以做到这一点,因为您在对象上放置了一个方法, javascript 让任何人都可以调用它。

如果您只想添加一个只能由方法调用的函数,您可以通过拥有一个作为对象的私有成员变量(请参阅 Crockford 如何实现它)来实现,您可以将方法放在该对象上。然后所有现有方法(按照 Crockford 在构造函数中建议访问私有成员数据的方式实现)可以调用这些方法。从技术上讲,它们是不同对象的成员,但如果需要,可以授予对对象实例数据的私有访问权限。

这一切都非常复杂,所以如果你描述了你真正想要解决的问题,你可能会得到一个更好的答案。

于 2012-04-04T23:23:21.320 回答
0

我不认为你能做到这一点。考虑以下代码:

function foo() {
    var privateVar = 10;            
    this.privilegedMethod = function() {
         return privateVar;   
    }
}
var obj = new foo();

在这里,privilegedMethod可以访问privateVar,因为它是定义方法时创建的闭包的一部分。当然,您总是可以在实例化后将新方法附加到对象:

obj.newMethod = function() { return "hello" };
alert(obj.newMethod()); // alerts "hello"

但是这种新方法将无法访问privateVar.

于 2012-04-04T23:23:41.647 回答