4 回答
TA贡献1843条经验 获得超7个赞
函数声明时设置的默认参数值是在函数调用时计算赋值的,而不是在函数声明时赋值
我们可以看下下面的例子
function foo2(a, b = (function() { console.log(c); return function(){} })()) {
b();
}
foo2();
调用 foo2();
控制台将输出:
Uncaught ReferenceError: c is not defined
at b (<anonymous>:1:47)
at foo2 (<anonymous>:2:5)
at <anonymous>:1:1
而不掉用 foo2();
控制台将不报错
以上例子说明了函数参数的默认值是在调用是赋值的,而不是在声明时。
对于问题的代码,还有注意一点,y默认值函数声明中的x是绑定为函数声明中的参数x变量而不是foo外层作用域中的变量x
function foo(x, y = function() { x = 2; }) {
console.log("x1:"+x);
y();
console.log("x2:"+x);
}
foo();
输出
x1:undefined
x2:2
那么下面的代码输出2就好理解了
var x = 1;
function foo(x, y = function() { x = 2; }) {
x = 3;
y();
console.log(x);
}
foo(); // 2
TA贡献1783条经验 获得超4个赞
看到了很多答案,在大家的提示下 我去查了很多资料现在已经理解了这个结果。
var x = 1;
function foo(x, y = function() { x = 2; }) {
var x = 3;
y();
console.log(x);
}
foo() // 3
x // 1
以上的代码 作用域链如下:
以上的图涉及一个问题,那就是为什么foo的参数居然是自成一个作用域链?
这是因为es6规定:
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。
也就是说y中的x=2,因为y中是没有x变量的,所以向上一级查找,他的上一级就是传入的参数x,因此y函数的作用改变的是参数x
而当foo内部var x=3时,这时内部的x已经覆盖掉了参数x,
console.log查找的是它的上一层foo的内部变量作用域x,这个x是等于3的,因此foo执行为3,一下贴出作用域链的一个概念,觉得解释的非常好
作用域链:作用域链是一个对象列表或者链表,这组对象定义了这段代码’作用关于中’的变量。当javascript需要查找变量x的值得时候(变量解析),他会从链中的第一个对象开始查找,如果这个对象有一个名为x的属性,则会直接使用这个属性的值,如果第一个对象中不存在名为x的属性,javascript会继续查找链上的下一个对象。如果第二个对象依然没有名为x的属性,则会继续查找下一个对象,以此类推。如果作用域链上没有任何一个对象含有属性x,那么久认为这段代码的作用域链上不存在x,并最终爆出一个引用错误异常。(犀牛书P59)
而第二段代码:
var x = 1;
function foo(x, y = function() { x = 2; }) {
x = 3;
y();
console.log(x);
}
foo() // 2
x // 1
作用域链如下:
foo中的console.log(x)中的x会查到他的上一级传入的参数x,因为传入的参数被y函数改为2,所以输出2
而第一个例子中的x上一级作用域链直接是新定义的x=3所以输出3
添加回答
举报