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條經驗 獲得超4個贊
我必須升級 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() { /* ... */ };
添加回答
舉報