0

我对此进行了一些研究,但我并不希望这是可能的,但也许你们中间有一个 JS 向导对如何解决这个问题有一个想法。

我有一个这样的 JS 函数:

{
    loadConfiguration: function(){
      theConfig.oneConfigOption = true;
      theConfig.anotherConfigOption = false;
    }
}

这是旧软件部分中的一种界面。截至目前,theConfig一直是一个全局变量。因为我不喜欢全局变量,所以我想theConfig从函数外部定义对象。

问题是,出于向后兼容的原因,函数的签名必须始终保持不变function(),并且必须始终命名需要设置对象的引用,theConfig以便上述代码仍然是有效的配置加载器。实际上,我无法更改此代码块所在的文件中的任何内容。

我唯一可以更改的地方是调用函数的位置(因为它是在另一个文件中调用的,可以从一个版本更新到另一个版本:

loadConfiguration();

我可以在这里做任何事情.. 包装函数、闭包或类似的东西。所以我的问题是,你能想出一种方法来强制对theConfigof的引用loadConfiguration指向我在调用函数时定义的对象而不更改其签名吗?

4

1 回答 1

0

我真的不确定你的目标是什么,但如果你被允许摆脱theConfig(使用它的版本不是window.theConfig)等等,那么你可以使用 IIFE。

var funcs = {
    loadConfiguration : (function () {
        var theConfig = {};

        //or, if you prefer...
        theConfig = some.object.somewhere.else.config;
        return function () {
        // this now resolves to the `theConfig` which is in the closure
        // created by the IIFE
            theConfig.one = true;
        };
    }());
};

您甚至可以使用该 IIFE 传递theConfig. 这里要注意的重要一点是,theConfig 在这些 IIFE 运行之前必须存在

loadConfiguration : (function (theConfig) {
    return function () { theConfig.x = 3; };
}(newConfigObject))

如果这些都不是您想要的,那么请更具体地说明您想从中获得什么。

编辑

根据你的更新,我有一个可怕的想法,理论上可行。
它很丑,很像忍者,而且我不一定会在我的最终产品中加入它。
也就是说,它应该是可以预测的,*只要您要替换的功能不需要访问闭包* -this可以使用 call 或 apply 来破解,但如果该功能试图访问其他东西是一个全局的(或者更糟的是,在闭包中定义,虽然它看起来不像),那么 THOSE 也需要被导入。

看看: // 你的“loadConfig”当前所在的地方 var codeblock = { // 我们想要交换 target_func 值的函数: function () { theVar.prop = 1; theVar.attr = 2; } }; // 我们要使用的新配置对象 var alternate = { config : {} };

// this whole thing would get injected somewhere into the page
// put it where you're about to fire your stuff
(function () {
    // the name of the variable doesn't actually matter right here
    // but I'm doing it for consistency
    var theVar = alternate.config,
        // grabbing the function as a string
        string = codeblock.target_func.toString(),
        // using regex to remove the `"function anonymous() {" + "}"` wrapper
        bare_func = string.replace(/^function[^{]+{/, "")
                          .replace(/}$/,""),

        // using the new Function constructor to pass in "theVar" (where the name matters)
        // the constructor doesn't accept closures, but any function that is created inside of the constructor does
        // so we return a new function (with the exact contents of the original function
        // but now, `theVar` is a parameter we're passing in 
        new_func = new Function ("theVar", "return function () {" + bare_func + "};"),
        // this is the new function returned from the constructor, and we're passing in "theVar"
        // again, name on the outside doesn't matter -- name in the `new Function` constructor DOES
        enclosed = new_func(theVar);

    // putting the function back where we stole it from
    codeblock.target_func = enclosed;
}());

如果我们codeblock.target_func();之前跑过,它会设置

window.theVar.prop = 1;
window.theVar.attr = 2;

...但是如果我们现在调用该函数...

codeblock.target_func();

alternate.config.prop;  // 1
alternate.config.attr;  // 2
于 2013-02-18T10:15:49.387 回答