【02】块级作用域

【02】块级作用域
 
魔芋总结:
为什么要有块级作用域?
  • 01,内层变量覆盖外层变量,因为变量提升。函数提升。
  • 02,用来计数的循环变量泄露为全局变量。循环结束后,它并没有消失,泄露成了全局变量。
 
03,ES6允许块级作用域的任意嵌套。
04,内层作用域可以和外层作用域定义同名的变量。
05,立即执行匿名函数(IIFE)不再必要了。
06,函数的作用域,在其定义的块级作用域之内。
 
需要注意的是,如果在严格模式下,函数只能在顶层作用域和函数内声明,其他情况(比如if代码块、循环代码块)的声明都会报错。
 
 
 

 
块级作用域
为什么需要块级作用域?
ES5只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。
 
第一种场景,内层变量可能会覆盖外层变量。
var tmp = new Date();

function f(){
  console.log(tmp);
  if (false){
    var tmp = "hello world";
  }
}

f() // undefined
 
上面代码中,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。
 
 
第二种场景,用来计数的循环变量泄露为全局变量。
var s = 'hello';

for (var i = 0; i < s.length; i++){
  console.log(s[i]);
}

console.log(i); // 5
 
上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
 
ES6的块级作用域
let实际上为JavaScript新增了块级作用域。
function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}
 
上面的函数有两个代码块,都声明了变量n,运行后输出5。这表示外层代码块不受内层代码块的影响。如果使用var定义变量n,最后输出的值就是10。
 
ES6允许块级作用域的任意嵌套。
{{{{{let insane = 'Hello World'}}}}};
 
上面代码使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量。
{{{{{let insane = 'Hello World'}
  console.log(insane); // 报错
}}}};
 
内层作用域可以定义外层作用域的同名变量。
{{{{let insane = 'Hello World';{let insane = 'Hello World';}}}}};
 

 
 
 
块级作用域的出现,实际上使得获得广泛应用的立即执行匿名函数(IIFE)不再必要了。
// IIFE写法
(function () {var tmp = ...;...}());
// 块级作用域写法
{let tmp = ...;...}
 
 
 

另外,ES6也规定,函数本身的作用域,在其所在的块级作用域之内。
function f() {
	console.log('I am outside!');
}
(function () {
	if (false) { // 重复声明一次函数f
		function f() {
			console.log('I am inside!');
		}
	}
	f();
}());
 
 
上面代码在ES5中运行,会得到“I am inside!”,但是在ES6中运行,会得到“I am outside!”。这是因为ES5存在函数提升,不管会不会进入 if代码块,函数声明都会提升到当前作用域的顶部,得到执行;而ES6支持块级作用域,不管会不会进入if代码块,其内部声明的函数皆不会影响到作用域的外部。
 
{
  let a = 'secret';
  function f() {
    return a;
  }
}
f() // 报错
 
上面代码中,块级作用域外部,无法调用块级作用域内部定义的函数。如果确实需要调用,就要像下面这样处理。
let f;{let a = 'secret';
  f = function () {return a;}}f(); // "secret"
 

原文作者:阮一峰
 
 

**

原文地址:https://www.cnblogs.com/moyuling/p/8992514.html