闭包和作用域一看就会

94 阅读2分钟

最近看到一道题挺有意思,话不多说,直接上题目:

var a = 0,  
b = 0; 

function A(a) {  
    A = function (b) {  
        console.log(a + b++);  
    };
    console.log(a++);  
}  

A(1);
A(2);
console.log(a);
console.log(b);

输出结果:

1
4
0
0

题目解析: 这段代码的行为可能会让初学者感到困惑,因为它涉及到函数重定义和闭包的概念。让我们逐步分析这段代码的执行过程。

首先,定义了两个全局变量 a 和 b,但在这段代码中,全局变量 b 实际上没有被使用。

接着,定义了一个名为 A 的函数,它接受一个参数 a。但是,在函数体内,A 被重新定义为一个新的函数,这个新函数接受一个参数 b 并打印 a + b++ 的结果。这里有几个关键点需要注意:

  1. 当 A 第一次被调用时(A(1);),它首先执行原始定义的函数体,其中 console.log(a++); 会打印出 1(因为参数 a 传递的是 1),然后 a 的值会增加到 2(但由于这是参数 a,它不会影响全局变量 a 的值)。
  2. 在原始函数体内,A 被重新定义为一个新的函数,这个新函数会捕获外部函数(即原始 A 函数)的局部变量 a 的值。由于 JavaScript 的闭包特性,这个新函数中的 a 将保持为 2(即原始 A 函数被调用时参数 a 的最终值)。
  3. 当 A 第二次被调用时(A(2);),由于 A 已经被重新定义为一个新的函数,所以它将执行这个新函数的逻辑。这个新函数会打印 a + b++ 的值,但这里的 a 是闭包中捕获的 2,而 b 是新函数的参数,传递的是 2。因此,它会打印 2 + 2 = 4,然后 b 的值会增加到 3(但这个值在函数外部是不可见的,因为它只存在于新函数的局部作用域中)。