作用域是指在程序中定义变量的区域,该位置决定了变量的生命周期。通俗地理解,作用域就是变量与函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期。
1 在 ES6 之前,ES 的作用域只有两种:
1 全局作用域中的对象在代码中的任何地方都能访问,其生命周期伴随着页面的生命周期。<br />2 函数作用域就是在函数内部定义的变量或者函数,并且定义的变量或者函数只能在函数内部被访问。函数执行结束之后,函数内部定义的变量会被销毁。
其他语言一般都支持块级作用域, ES却没有,同时又因为j变量提升,很容易出现其他问题:
1.1 变量容易在不被察觉的情况下被覆盖掉
var myname = "极客时间"
function showName(){
console.log(myname);
if(0){
var myname = "极客邦"
}
console.log(myname)
}
showName()
// undefied
// undefied
// 另一个变量提升例子
function varTest() {
var x = 1;
if (true) {
var x = 2; // 同样的变量!
console.log(x); // 2
}
console.log(x); // 2
}
1.2 本应销毁的变量没有被销毁
function foo(){
for (var i = 0; i < 7; i++) {
}
console.log(i);
}
foo()
像变量i这些用在循环遍历的临时变量,执行完遍历后还会保留下来,这会污染变量环境。
2 ES6块级作用域
2.1 块级作用域
就是使用一对大括号包裹的一段代码,比如函数、判断语句、循环语句,甚至单独的一个{}都可以被看作是一个块级作用域。
//if块
if(1){}
//while块
while(1){}
//函数块
function foo(){}
//for循环块
for(let i = 0; i<100; i++){}
//单独一个块
{}
2.2 ES6 引入了 let 和 const 关键字,从而使 JavaScript 也能像其他语言一样拥有了块级作用域。
function letTest() {
let x = 1;
if (true) {
let x = 2; // 不同的变量
console.log(x); // 2
}
console.log(x); // 1
}
2.3 JavaScript 是如何支持块级作用域的
JavaScript 引擎是通过变量环境实现函数级作用域的, 如何实现对块级作用域的支持
function foo(){
var a = 1
let b = 2
{
let b = 3
var c = 4
let d = 5
console.log(a)
console.log(b)
}
console.log(b)
console.log(c)
console.log(d)
}
foo()
在同一段代码中,ES6 是如何做到既要支持变量提升的特性,又要支持块级作用域的
2.3.1
2.3.2
2.3.3
2.3.4
2.4 总结
块级作用域就是通过词法环境的栈结构来实现的,而变量提升是通过变量环境来实现,通过这两者的结合,JavaScript 引擎也就同时支持了变量提升和块级作用域了。
3 let/const不存在变量提升
4 暂时性死区
只要块级作用域存在let/const命令,则它声明的变量就被绑定binding在这个区域,也就是这个区块对这些变量一开始就形成封闭作用域,不再受外部印象(参考ES6深入浅出)
只要在声明之前使用变量,就会报错。
let myname= '极客时间'
{
console.log(myname)
let myname= '极客邦'
}
这个ES6明确规定,跟上面词法环境分析存在相违背,词法分析,执行进入到块级作用域,就会把let、cosnt声明的变量压人词法栈中,已经在内存中了,那为啥使用不了??