2 回答
TA贡献1836条经验 获得超4个赞
这通常称为猴子补丁
神圣真实。
你不能,除非你以某种方式暴露这个隐私。
正确的。我只是不想将该方法直接公开到window
作用域中。我认为解决方案可以更优雅。
看来你可以更改源代码
好吧,正如您已经注意到的那样,这很令人困惑,但重点是,我自己也不确定。我必须保留默认的模块行为,但我希望我可以稍微扩展该模块,以帮助应用这个猴子补丁。
如果您想了解完整的故事,有一个运行 WebApp 的 IoT 设备,它使用我们讨论的模块将微控制器寄存器状态转换为 DOM 视图。我们称之为registers_into_view
模块。
通过复制相同的模块,创建了一个 Web 服务器,其中:
接收微控制器内存转储
模块的副本
registers_into_view
创建一个模型视图(通常应该发生在前端)向视图发送 JSON 形式
通过扩展相同的 Web 应用程序,创建了“云”Web 应用程序,其中:
否定现有
registers_into_view
模块,而是接收后端传来的View数据
直接将其应用到 DOM 中
通常情况下,我会重构整个架构:
registers_into_view
删除后端模块的副本registers_into_view
在前端重用现有模块
但使用该堆栈的 A 公司拒绝这样做。现有架构对他们来说可以使用 6 年。事实上,他们的经理避免进行重大变革,因为创建该软件的 B 公司收取了大量费用。所以他们没有重构的动力。
嗯,我有。我在 C 公司工作,我们将销售相同的物联网设备。
我们还想使用现有的前端 Web 应用程序。
为了满足这一需求,我扩展了现有的物联网服务器以支持这些设备及其前端。
所以我必须使用另一种语言和框架复制另一个服务器 API 合约。
现在,我不想重新创建registers_into_view
在后端服务器上运行的 1500 LoC 模块,而是将现有registers_into_view
模块导入“云”Web 应用程序并对其进行猴子修补以从 JSON 而不是内存转储(我们的private_method
)中检索寄存器数据。
入侵应该尽可能少,以提高我的补丁被合并的机会。
现在我希望我的动机足够明确。我发现它对每个人来说并不是那么有趣,因此尝试从上下文中清除编程任务。
让我们来看看解决方案。
你的解决方案2
我无法更改public_method
模块的 ,因为实际上它运行大约 50 个其他私有方法,这些方法都retreive_data_method
仅使用不同的请求进行调用,并将结果放在 DOM 中的不同位置。
解决方案1
奇迹般有效。如此简单和优雅。我将根据我的需要稍微简化一下:
var module = module || function (){
function public_method(){private_method()}
function private_method(){console.log("original private method")}
return {
public_method: public_method,
// this function allows to update the private_method in runtime
replace_private_method: function(fn) {
// Function declarations effectively create variables;
// you can simply write to them:
private_method = fn;
}
}
}()
// original behavior
module.public_method()
// patching
module.replace_private_method(function() {console.log("I've been monkey patched")});
// new behavior
module.public_method()
我没有像您的解决方案中那样直接替换,而是尝试将模块上下文保存在某个公开的变量中,并通过它找到私有方法。这没有用。
谢谢。
TA贡献1872条经验 获得超3个赞
我必须升级 1500 LoC JS 模块中的一个小型私有函数,该函数是用“揭示模块模式”编写的。
我认为你的意思是你必须在运行时从“模块”函数之外执行此操作。这通常称为“猴子修补”。
你不能,除非你以某种方式暴露这个隐私。
我发现的唯一可行的解决方案是重写
function private_method(){}
将this.private_method = function(){...}
其绑定到窗口的内容,这样我就可以在运行时更改它。
如果你能做到这一点,那么看来你可以更改源代码。
但如果你可以改变源代码,那么你可以这样做(见***
评论):
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() { /* ... */ });
您可以通过将所有私有方法放在您通过其调用的对象上来概括(并且可以说是简化),但这意味着要么使用与预期不同的方式调用它们,要么使这些调用更加尴尬this:
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() { /* ... */ };
添加回答
举报