Javascript 在闭包中更改函数的行为

Javascript 在闭包中更改函数的行为,javascript,closures,refactoring,private-methods,Javascript,Closures,Refactoring,Private Methods,我必须升级一个1500 LoC JS模块中的一个小私有函数,用 简化的任务如下所示: var模块=模块| |函数(){ 函数init(){ //您可以随时升级init,以便稍后在运行时替换private_方法 (函数not_important(){console.log(“我做一些其他事情”)})() } 函数公共_方法(){ 私有_方法() } 函数私有_方法(){ log(“原始私有方法”) } //您也可以在此处添加任何方法 返回{ init:init, 公共法:公共法, //并揭露他们

我必须升级一个1500 LoC JS模块中的一个小私有函数,用

简化的任务如下所示:

var模块=模块| |函数(){
函数init(){
//您可以随时升级init,以便稍后在运行时替换private_方法
(函数not_important(){console.log(“我做一些其他事情”)})()
}
函数公共_方法(){
私有_方法()
}
函数私有_方法(){
log(“原始私有方法”)
}
//您也可以在此处添加任何方法
返回{
init:init,
公共法:公共法,
//并揭露他们
}
}()
/**这是页面上的另一个脚本,它使用原始模块*/
module.public\u method()//返回“原始私有方法”
/**第三个脚本,只在某些环境中运行,要求模块的工作方式稍有不同*/
//在这里做任何JS魔术来代替私有方法吗
//或者调用module.init(方法\u到\u替换\u私有\u方法)
module.public\u method()//我想在这里看到private\u方法的一些其他行为
我学习过


已经有问题了,看起来与我的任务最相关,但没有成功

我找到的唯一可行的解决办法是重写
function private_method(){}
this.private_method=function(){…}
,它将它绑定到窗口,因此我可以在运行时更改它

但我不会这样做,因为这个方法不再是私有的,我无法预测旧的100000 LoC意大利面怪物应用程序(用老式ECMAScript 5编写)中会出现什么问题

更新
这是答案上的答案

首先,感谢你的详细回答,T.J.克劳德

这通常被称为monkeypatching

真是太好了

你不能,除非你以某种方式揭露那个秘密

对。我只是不想将该方法直接暴露在
窗口中。我认为解决方案可以更优雅一些

看起来您可以更改源代码

正如你们已经注意到的,这让人困惑,但问题是,我自己还不确定。 我必须保持默认的模块行为,但我希望我可以扩展模块一点,以帮助应用这个猴子补丁

如果你想了解全部情况,有一个IoT设备运行WebApp,它使用我们讨论的模块将微控制器寄存器状态转换为DOM视图。我们将其称为
注册到\u视图中
模块

通过复制同一模块,创建了一个web服务器,该服务器:

  • 接收微控制器内存转储
  • 复制将_注册到_视图中
    模块创建一个模型视图(通常应发生在前端)
  • 将视图发送为JSON格式
通过扩展相同的web应用程序,创建了“云”web应用程序,该应用程序:

  • 将现有的
    寄存器注册到\u视图
    模块中,而不是
  • 从后端接收视图数据
  • 将其直接应用到DOM中
通常,我会重构整个体系结构:

  • 寄存器的副本删除到后端的\u视图
    模块中
  • 将现有的
    寄存器重新使用到前端的\u视图
    模块中
但使用该堆栈的A公司拒绝这样做。现有的模式为他们工作了6年。事实上,他们的管理者避免大的改变,因为开发这个软件的B公司收取了大量的费用。所以他们没有重构的动机

嗯,我有。 我在C公司工作,我们将销售相同的物联网设备。
我们还希望使用现有的前端WebApp。
为此,我扩展了现有的物联网服务器,以支持这些设备及其前端。
因此,我必须使用另一种语言和框架复制另一个服务器API合同

现在,我想将已经存在的
registers\u导入到\u view
模块中,并将其安装到“云”WebApp中,然后对其进行修补,从JSON而不是内存转储中检索寄存器数据(我们的
私有\u方法

入侵应该尽可能少,以提高我的补丁被合并的可能性

现在我希望我的动机足够清楚。我发现它对每个人都不是那么有趣,所以我试图从上下文中清理编程任务

让我们来讨论解决方案。 你的解决方案2 我无法更改该模块的
public\u方法
,因为实际上它运行约50个其他私有方法,这些方法都调用
retretrieve\u data\u方法
,只需使用不同的请求,并将结果放在DOM中的不同位置

解决方案1 工作起来很有魅力。如此简单和优雅。我将根据自己的需要对其进行简化:

var模块=模块| |函数(){
函数public_method(){private_method()}
函数private_method(){console.log(“原始私有方法”)}
返回{
公共法:公共法,
//此函数允许在运行时更新private_方法
替换私有方法:函数(fn){
//函数声明有效地创建变量;
//你可以简单地写信给他们:
私有_方法=fn;
}
}
}()
//原始行为
module.public_方法()
//修补
module.replace_private_方法(function(){console.log(“我被猴子打过补丁”)});
//新行为
module.public_方法()
与您的解决方案中的直接替换不同,我尝试将模块上下文保存在某个公开变量中,并通过它查找私有方法。这没用

谢谢

我必须升级一个1500 LoC JS模块中的一个小私有函数,该模块是以显示模块模式编写的

我认为这很有趣
var module = module || function (){
    function init(){
        (function not_important(){console.log("I do some other stuff")})()
    }

    function public_method(){
        private_method()
    }

    function private_method(){
        console.log("original private method")
    }

    return {
        init: init,
        public_method: public_method,
        // *** Provide yourself functions to get `private_method` (and any
        // others you may want) and update it
        __privates__: {
            private_method: {
                get: function() {
                    return private_method;
                },
                set: function(fn) {
                    // *** Function declarations effectively create variables;
                    // you can write to them:
                    private_method = fn;
                }
            }
        }
    }
}()

// *** Where you want to make your change
module.__privates__.private_method.set(function() { /* ... */ });
var module = module || function (){
    /*** An object with the private functions you need to do this for
    var privates = {};

    function init(){
        (function not_important(){console.log("I do some other stuff")})()
    }

    function public_method(){
        // *** Calling it via that object, which has an effect on `this`
        privates.private_method()
        // *** If you want `this` to be the same as it would have been
        // with the raw call above (the global object or `undefined` if
        // you're in strict mode), you can use the comma trick:
        // (0,privates.private_method)()
    }

    privates.private_method = function private_method(){
        console.log("original private method")
    };

    return {
        init: init,
        public_method: public_method,
        // *** Expose that object with the private functions
        __privates__: privates
    }
}()

// *** Where you want to make your change
module.__privates__.private_method = function() { /* ... */ };