JavaScript函数参数默认值为何表现不同?解析两种场景差异
为什么两段带参数默认值的JS代码执行结果不同?
这问题的核心其实是ES6函数参数默认值的一个特性:参数会创建一个独立的作用域,咱们一步步拆解两段代码的执行逻辑就清楚了。
先看代码1的执行过程
代码如下:
function foo(x = 2, y = function() { return x; }) { var x = 5; console.log(y()) // 输出2 } foo();
- 调用
foo()时,JS会先处理参数部分,这里会生成一个参数专属的作用域:- 参数
x被赋予默认值2,此时这个作用域里有个x变量,值是2。 - 参数
y的默认函数是在这个参数作用域里定义的,所以它会“记住”这个作用域,里面的x指向的就是参数作用域里的那个x。
- 参数
- 进入函数体后,
var x = 5其实做了两件事:- 变量提升:在函数体作用域的顶部提前声明了一个新的
x变量(和参数作用域的x完全是两个东西)。 - 给这个新的
x赋值为5。
- 变量提升:在函数体作用域的顶部提前声明了一个新的
- 当执行
y()时,函数y会去自己绑定的参数作用域找x,拿到的是最初的默认值2,所以控制台输出2。
再看代码2的执行过程
代码如下:
function foo(x = 2, y = function() { return x; }) { x = 5; console.log(y()) // 输出5 } foo();
- 同样,调用
foo()时先进入参数作用域:- 参数
x默认值为2,y的函数依然绑定参数作用域的x。
- 参数
- 进入函数体后,
x = 5没有用var/let/const声明变量,所以JS会沿着作用域链往上找:- 首先找到的就是参数作用域里的那个
x,直接把它的值改成5。
- 首先找到的就是参数作用域里的那个
- 执行
y()时,函数y从参数作用域拿到的是修改后的x值5,所以控制台输出5。
简单总结一下:
- 代码1里的
var x = 5是在函数体作用域重新声明了一个同名变量,和参数作用域的x互不干扰; - 代码2里的
x = 5是直接修改了参数作用域里的x,所以被y函数捕获到了变化。
内容的提问来源于stack exchange,提问作者jackie_pan
相关产品推荐
相关产品推荐

