首頁  >  問答  >  主體

為何在函數體內重新分配函數名會改變其行為?

我在逆向工程一些JavaScript時遇到了這個函數:

function fun1() {
    const arr = ["a", "b", "c", "d", "e"];
    fun1 = function () {
        return arr;
    };
    return fun1();
}

對我來說,它看起來是多餘的。這段程式碼似乎:

  1. 宣告了一個陣列arr
  2. 在函數內部重新定義函數,使其傳回arr
  3. 使用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()有什麼差別?

P粉270891688P粉270891688276 天前413

全部回覆(1)我來回復

  • P粉037880905

    P粉0378809052024-01-17 17:06:28

    當第一次呼叫時,您的 fun1() 函數重新定義了(相對)全域的 fun1 符號。它將原始函數更改為局部內部函數,該函數關閉了數組。因此,只涉及一個數組,即第一次呼叫 fun1() 時所建立的陣列。

    另一方面,您的 fun2() 每次呼叫時都會建立一個全新的陣列。

    如果您將fun1() 更改為將內部函數分配給一個局部聲明的 fun1 變量,它將與fun2() 的行為相同。

    回覆
    0
  • 取消回覆