问题 是否可以动态访问模块模式中的私有变量?


有没有办法从模块模式中动态访问私有变量的公共函数? test1显示了我对“动态访问”的含义,但使用了公共变量

var x = (function(){
    var x=0, y=2, z=5;

    return {
        toast: 123,
        test1: function(arg){
            return this[arg];
        },
        test2: function(){
            // ??
        }
    };
}());

console.log(x.test1("toast")); // 123
console.log(x.test2("y")); // should return 2

我最终创建了一个存储我的私有变量的私有变量(一个对象),所以我能够像这样访问它们

 privateVarStore[privateVarName]

但那还有另一种解决方案吗?


6117
2017-12-25 04:26


起源



答案:


DEMO

是。

很抱歉让Adam Rackis失望,但你可以做到( 邪恶)eval:

var x = (function(){
    var x=0, y=2, z=5;

    return {
        toast: 123,
        test1: function(arg){
            return this[arg];
        },
        test2: function(a){
            return eval(a)
        }
    };
}());

console.log(x.test1("toast")); // 123
console.log(x.test2("y")); // should return 2  -> does return 2

这是少数例外情况之一 eval 应该使用。

编辑,根据Hans B PUFAL建议(评论),您可以并且应该验证参数 test2 如下:

test2: function(a){
    return /^[$_a-z][$_a-z0-9]*$/i.test (a) ? eval(a) : undefined;
}

9
2017-12-25 05:36



为了避免安全问题,建议添加一个验证,即test2的参数确实是一个简单的变量:return /^[$_a-z][$_a-z0-9]*$/i.test(a)?评估(a):未定义; - HBP
@HansBPUFAL:好主意!我一定会加上它 - qwertymk
+1,但是我可以建议另一种验证方法:如果你定义一个对象,列出哪些私有变量可以通过公共函数访问,比如 var accessList = {"x":true,"y":true}; 然后在 function test2(a) 你可以说 return accessList[a] ? eval(a) : undefined;  - 这样做的好处是,它不仅可以提供关于哪些字符串可以传递给eval的安全性,还允许您定义其他无法访问的真正私有变量 test2()。 - nnnnnn
@nnnnnn - 我必须阅读几次,但这是一个非常酷的主意 - Adam Rackis
@qwertymk如果还没有附加eval方法怎么样。我以后不能附上它。我需要访问以抓取网页并访问变量。调试和暂停时,Chrome检查员可以访问。我或许可以与检查员沟通,做类似的事情,但有可能没有吗? - momo


答案:


DEMO

是。

很抱歉让Adam Rackis失望,但你可以做到( 邪恶)eval:

var x = (function(){
    var x=0, y=2, z=5;

    return {
        toast: 123,
        test1: function(arg){
            return this[arg];
        },
        test2: function(a){
            return eval(a)
        }
    };
}());

console.log(x.test1("toast")); // 123
console.log(x.test2("y")); // should return 2  -> does return 2

这是少数例外情况之一 eval 应该使用。

编辑,根据Hans B PUFAL建议(评论),您可以并且应该验证参数 test2 如下:

test2: function(a){
    return /^[$_a-z][$_a-z0-9]*$/i.test (a) ? eval(a) : undefined;
}

9
2017-12-25 05:36



为了避免安全问题,建议添加一个验证,即test2的参数确实是一个简单的变量:return /^[$_a-z][$_a-z0-9]*$/i.test(a)?评估(a):未定义; - HBP
@HansBPUFAL:好主意!我一定会加上它 - qwertymk
+1,但是我可以建议另一种验证方法:如果你定义一个对象,列出哪些私有变量可以通过公共函数访问,比如 var accessList = {"x":true,"y":true}; 然后在 function test2(a) 你可以说 return accessList[a] ? eval(a) : undefined;  - 这样做的好处是,它不仅可以提供关于哪些字符串可以传递给eval的安全性,还允许您定义其他无法访问的真正私有变量 test2()。 - nnnnnn
@nnnnnn - 我必须阅读几次,但这是一个非常酷的主意 - Adam Rackis
@qwertymk如果还没有附加eval方法怎么样。我以后不能附上它。我需要访问以抓取网页并访问变量。调试和暂停时,Chrome检查员可以访问。我或许可以与检查员沟通,做类似的事情,但有可能没有吗? - momo


没有 (至少不是没有诉诸 eval,根据qwertymk的回答)。

y 不属于 x (考虑将这个对象命名为比 x 避免与局部变量混淆 x)。 y 是一个局部变量 x的方法形成了封闭。

任何 x的方法可以访问 y,但不是说 this.y而是通过访问 y 直。

再次, y 不是您对象的属性 x。它只是创建的函数中的局部变量 x从而导致 x形成封闭的方法。

所以,得到 test2 回来 y, 做就是了:

test2: function(){
    return y;
}

要创建允许您访问私有变量的方法,请考虑以下内容:

var x = (function () {
    var privateMembers = { x: 0, y: 2, z: 5 };

    return {
        getPrivate: function (name) {
            return privateMembers[name];
        },
        toast: 123,
        test1: function (arg) {
             return this[arg];
        },
        test2: function () {
           // ??
        }
    };
})();

接着

alert(x.getPrivate("y")); //alerts 2

查看 这个小提琴


7
2017-12-25 04:28



你会如何推荐Tim解决丢失的代码? test2()? - mauris
很好的答案,但这是我的替代解决方案(创建一个私有对象,以便在公共函数中访问我的私有变量),我想知道是否还有另一种(更美丽)的方式呢? - Tim Friedrich
@Tim - 不是我能想到的。我个人认为以上方式更漂亮:) - Adam Rackis
有人可以这么说 test2 是一个吸气鬼 y。通常,它可能会被命名 getY。 - Steve Jorgensen
@TimFriedrich - 史蒂夫上面的评论很好。根据您对test2的真正意图,考虑重命名。 - Adam Rackis