我在逆向工程一些JavaScript時遇到了這個函數:
function fun1() { const arr = ["a", "b", "c", "d", "e"]; fun1 = function () { return arr; }; return fun1(); }
對我來說,它看起來是多餘的。這段程式碼似乎:
arr
。 arr
。 return fun1()
傳回函數本身的結果,現在重新定義為傳回arr
,所以這似乎回傳arr
。 因此,我重寫了這個函數,並消除了所有多餘的程式碼:
function fun2() { const arr = ["a", "b", "c", "d", "e"]; return arr; }
然而,我驚訝地發現這兩個函數的行為完全不同。
fun1()
似乎傳回對arr
的引用,而fun2()
似乎回傳arr
的副本。
這裡有一個可運行的最小可複現範例來說明差異:
// This function is redefined inside itself to return arr function fun1() { const arr = ["a", "b", "c", "d", "e"]; fun1 = function() { return arr; }; return fun1(); } // Why not return arr directly? function fun2() { const arr = ["a", "b", "c", "d", "e"]; return arr; } // But the result is different... let test_fun_1 = fun1(); test_fun_1.pop(); test_fun_1 = fun1(); console.log("Logging test_fun_1"); console.log(test_fun_1); // ["a", "b", "c", "d"] let test_fun_2 = fun2(); test_fun_2.pop(); test_fun_2 = fun2(); console.log("Logging test_fun_2"); console.log(test_fun_2); // ["a", "b", "c", "d", "e"] // What is this magic?
看起來像是發生了魔法...
fun1()
和fun2()
有什麼差別?
當第一次呼叫時,您的
fun1()
函數重新定義了(相對)全域的fun1
符號。它將原始函數更改為局部內部函數,該函數關閉了數組。因此,只涉及一個數組,即第一次呼叫fun1()
時所建立的陣列。另一方面,您的
fun2()
每次呼叫時都會建立一個全新的陣列。如果您將
fun1()
更改為將內部函數分配給一個局部聲明的fun1
變量,它將與fun2()
的行為相同。