猿问

为什么以下两个例子执行结果不同?

var x = 1;

function foo(x, y = function() { x = 2; }) {

  var x = 3;

  y();

  console.log(x);

}


foo() // 3

x // 1

而去掉var以后:


var x = 1;

function foo(x, y = function() { x = 2; }) {

  x = 3;

  y();

  console.log(x);

}


foo() // 2

x // 1

为什么实例一的y执行完成没有改变任何x的值?

而去掉var输出结果就会改变?


一只萌萌小番薯
浏览 514回答 4
4回答

蓝山帝景

函数声明时设置的默认参数值是在函数调用时计算赋值的,而不是在函数声明时赋值我们可以看下下面的例子function foo2(a, b = (function() { console.log(c); return function(){} })()) {&nbsp; &nbsp; b();}foo2();调用 foo2();控制台将输出:Uncaught ReferenceError: c is not definedat b (<anonymous>:1:47)at foo2 (<anonymous>:2:5)at <anonymous>:1:1而不掉用 foo2();控制台将不报错以上例子说明了函数参数的默认值是在调用是赋值的,而不是在声明时。对于问题的代码,还有注意一点,y默认值函数声明中的x是绑定为函数声明中的参数x变量而不是foo外层作用域中的变量xfunction foo(x, y = function() { x = 2; }) {&nbsp; console.log("x1:"+x);&nbsp; y();&nbsp; console.log("x2:"+x);}foo();输出&nbsp;x1:undefinedx2:2那么下面的代码输出2就好理解了var x = 1;function foo(x, y = function() { x = 2; }) {&nbsp; x = 3;&nbsp; y();&nbsp; console.log(x);}foo(); // 2

慕娘9325324

看到了很多答案,在大家的提示下 我去查了很多资料现在已经理解了这个结果。var x = 1;function foo(x, y = function() { x = 2; }) {&nbsp; var x = 3;&nbsp; y();&nbsp; console.log(x);}foo() // 3x // 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; }) {&nbsp; x = 3;&nbsp; y();&nbsp; console.log(x);}foo() // 2x // 1作用域链如下:foo中的console.log(x)中的x会查到他的上一级传入的参数x,因为传入的参数被y函数改为2,所以输出2而第一个例子中的x上一级作用域链直接是新定义的x=3所以输出3
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答