今天在读《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. 函数的输出结果变化在根本上是作用链域的变化