ES5作用域
ES5中只有全局作用域和函数作用域,没有块级作用域。这样就会导致内层变量可能会覆盖外层变量以及用来计数的循环变量泄露为全局变量。
1. `var tmp = new Date();`
1. ``
1. `function f() {`
1. `console.log(tmp);`
1. `if (false) {`
1. `var tmp = 'hello world';`
1. `}`
1. `}`
1. ``
1. `f(); // undefined`
if代码块的外部使用外层的tmp变量,内部使用内层的tmp变量。但是,函数f执行后,输出结果为undefined,原因在于函数预编译时var声明的变量提升,导致内层的tmp变量覆盖了外层的tmp变量。
1. `var s = 'hello';`
1. ``
1. `for (var i = 0; i < s.length; i++) {`
1. `console.log(s[i]);`
1. `}`
1. ``
1. `console.log(i); // 5`
变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
ES6 的块级作用域
1.ES6 允许块级作用域的任意嵌套,嵌套的块级作用域,每一层都是一个单独的作用域。内层作用域可以定义外层作用域的同名变量但是同一层块级作用域的变量不能被重复声明,且外层作用域无法读取到内层作用域的内部变量。
{{
let a="hello";
{
let a="hello";
}
}}
2.ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
1. `// 第一种写法,报错`
1. `if (true) let x = 1;`
1. ``
1. `// 第二种写法,不报错`
1. `if (true) {`
1. `let x = 1;`
1. `}`
1. `// 不报错`
1. `'use strict';`
1. `if (true) {`
1. `function f() {}`
1. `}`
1. ``
1. `// 报错`
1. `'use strict';`
1. `if (true)`
1. `function f() {}`
块级作用域变量声明
块级作用域中let和const声明的变量在声明之前使用(赋值和访问取值等)都会报错。块级作用域中let和const声明的变量只在该作用域有效,外部不能访问否则会报错。
而var声明的变量预编译时会发生变量提升到全局作用域赋值为undefined。
在块级作用域中默认声明的变量(不用var、let声明),只有代码执行到声明语句之后,才可以进行访问,否则会报错。在块级作用域中默认声明的变量会被提升到全局作用域(但是要在声明语句之后才能被访问到)
块级作用域与函数声明
允许在块级作用域内声明函数。
函数声明类似于var声明的变量,会提升到全局作用域或函数作用域的头部,只会提升函数名不会提升函数体作为值。同时,函数声明还会函数整体提升到所在的块级作用域的头部,即函数名和函数体都会提升到块级作用域的头部。