今天在读《ES6标准入门》的时候,发现了两段很有意思的代码:

 1 var x = 1
 2 function foo(x, y = function () {
 3     x = 2
 4 }) {
 5     var x = 3
 6     y()
 7     console.log(x)
 8 }
 9 
10 foo()   // 3
11 console.log(x)  // 1
 1 var x = 1
 2 function foo(x, y = function () {
 3     x = 2
 4 }) {
 5     x = 3
 6     y()
 7     console.log(x)
 8 }
 9 
10 foo()   // 2
11 console.log(x)  // 1

  可以看到,仅仅是改变了第3行 x 变量的修饰语句,结果就发生了很大的变化,而发生这个变化的关键因素就是在这个过程中,变量的作用域发生了变化,要理解其中发生的原理,首先要明白一个函数作用域的基本知识,如下面图片所示:

  

  理解的过程如下面代码所示:

 1 var x = 1
 2 function foo(x, y = function () {
 3     console.log(x) // undefined
 4     x = 2
 5 }) {
 6     var x = 3
 7     y()
 8     console.log(x)
 9 }
10 
11 foo()   // 3
12 console.log(x)  // 1

  第3行输出undefined的原因:因为在该函数内,x没有被定义,则x的值由上一级作用域(foo函数参数作用域)决定,因此x就是foo函数参数的值x,因为没有传递参数,所以x的值为undefined

  第11行输出的结果为3的原因:在第6行定义了x变量,因此在第8行的x的取值是在函数内部作用域,即取值为第6行(x = 3);此时第7行执行的y函数虽然对x变量做了处理,但是处理的是函数参数的x(函数参数作用域内的x),并不是函数内部作用域的x。

 1 var x = 1
 2 function foo(x, y = function () {
 3     console.log(x) // 3
 4     x = 2
 5 }) {
 6     x = 3
 7     y()
 8     console.log(x)
 9 }
10 
11 foo()   //
12 console.log(x)  // 1

  第3行输出3的原因:第6行对于x进行了赋值,此时的x由于在函数内部没有被定义,因此该x表示的是函数参数(函数参数作用域)的x,而第3行,第8行在该情况下均是对函数参数的x进行操作。

 

结论:

  1.一个函数的作用域分为函数参数作用域和函数内部作用域

  2. 函数的输出结果变化在根本上是作用链域的变化