亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

改變閉包中函數的行為

改變閉包中函數的行為

拉莫斯之舞 2023-10-14 18:28:48
我必須升級 1500 LoC JS 模塊中的一個小型私有函數,該函數是用The Revealing Module Pattern編寫的。簡化的任務如下所示:var module = module || function (){    function init(){        // you can upgrade init anyhow to be able to replace private_method later in runtime        (function not_important(){console.log("I do some other stuff")})()    }    function public_method(){        private_method()    }    function private_method(){        console.log("original private method")    }    // you can add any methods here, too    return {        init: init,        public_method: public_method,        // and expose them    }}()/** this is another script on the page, that uses original module */module.public_method()  // returns "original private method"/** the third script, that runs only in some environment, and requires the module to work a bit different */// do any JS magic here to replace private_method// or call module.init(method_to_replace_private_method)module.public_method()  // I want to see some other behavior from private_method here我研究過訪問閉包捕獲的變量如何從閉包中獲取對象?已經有問題了,這看起來與我的任務最相關,但沒有成功。我發現的唯一可行的解決方案是重寫 function private_method(){}將this.private_method = function(){...}其綁定到窗口的內容,這樣我就可以在運行時更改它。但我不會走這條路,因為該方法不再是私有的,而且我無法預測用舊式 ECMAScript 5 編寫的舊 100000 LoC 意大利面怪物應用程序中可能會出現什么問題。
查看完整描述

2 回答

?
HUH函數

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()

我沒有像您的解決方案中那樣直接替換,而是嘗試將模塊上下文保存在某個公開的變量中,并通過它找到私有方法。這沒有用。


謝謝。


查看完整回答
反對 回復 2023-10-14
?
守著一只汪

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() { /* ... */ };


查看完整回答
反對 回復 2023-10-14
  • 2 回答
  • 0 關注
  • 123 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號