以下大部分为学习《JavaScript 高级程序设计》(第 3 版) 所做笔记。
JS 没有块级作用域的概念,在块语句中创建的变量,实际上是在包含函数中而非语句中创建的。
看下面的语句,在 fn() 中定义了一个 for 循环,如果是在 Java、C++等语言中,循环结束后 变量 i 就会被销毁。可是在 JS 中,变量 i 是定义在 fn() 的活动对象中的,因此从它有定义开始,就可以在函数内部随处访问它。
1 <script>
2 function fn( count ){
3 for( var i=0; i<count; i++ ){
4 console.log( i );
5 }
6 console.log( i );
7 }
8 fn( 2 );
9 /*输出:
10 0
11 1
12 2
13 */
14 </script>
JS 从来不会告诉你是否多次声明了同一个变量,如果错误地重新声明同一个变量,也不会改变变量的值,遇到这种情况,它只会对后续的声明视而不见。
1 <script>
2 function fn( count ){
3 for( var i=0; i<count; i++ ){
4 console.log( i );
5 }
6 var i; //重新声明变量
7 console.log( i );
8 }
9 fn( 2 );
10 /*输出:
11 0
12 1
13 2
14 */
15 </script>
如果想要模仿块级作用域,可以使用匿名函数。
(立即执行函数相关的笔记:https://www.cnblogs.com/xiaoxuStudy/p/12354095.html#IIFE)
1 <script>
2 function fn( count ){
3 //使用立即执行函数
4 (function(){
5 for( var i=0; i<count; i++ ){
6 console.log( i );
7 }
8 })();
9 console.log( i ); //导致一个错误。报错:Uncaught ReferenceError: i is not defined at fn
10 }
11 fn( 2 );
12 </script>
上面在 for 循环外部插入了一个私有作用域。在匿名函数中定义的任何变量,都会在执行结束时被销毁。因此,变量 i 只能在循环中使用,使用后即被销毁,而在私有作用域中能够访问变量 count,是因为这个匿名函数是一个闭包,它能够访问包含作用中的所有变量。这种做法可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以销毁其作用域链了。
这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。一般来说,应该少向全局作用域中添加变量和函数。在一个由很多开发人员共同参与的大型应用程序中,过多的全局变量和函数很容易导致命名冲突。通过创建私有作用域,每个开发人员既可以使用自己的变量,又不用担心搞坏全局作用域。