1.var缺陷
- var 声明的变量会导致变量提升,变量提升带来一下两个问题:
- 变量容易在不被察觉的情况下被覆盖掉
var myname = "极客时间"
function showName(){
console.log(myname);
if(0){
var myname = "极客邦"
}
console.log(myname);
}
showName() // undefined
函数showName代码在编译后生成执行上下文,其变量myname会被保存在环境变量对象中,初始值为undefined,即使执行代码时判断语句里面没有执行给myname赋值,还是会得到undefined,而不是往上面作用域找(本作用域存在用本作用于的)
- 本应销毁的变量没有销毁
function foo () {
for (var i=0; i < 7; i++) {
}
console.log(i) // 7
}
在c语言等绝大多数代码中,for循环结束之后 i 会销毁,而JavaScript没有销毁,输出7
2.三种作用域
- 全局作用域
- 函数作用域
- 块级作用域:利用let和const来支持块级作用域
3.执行上下文角度看块级作用域
function foo(){
var a = 1
let b = 2
{
let b = 3
var c = 4
let d = 5
console.log(a) // 1
console.log(b) // 3
}
console.log(b) // 2
console.log(c) // 4
console.log(d) // ReferenceError: d is not defined
}
foo()
foo函数执行上下文:
- 函数内部通过var声明的变量,在编译阶段全被存放到变量环境中
- 通过let声明的变量,在编译阶段会被存放到词法环境中
执行到代码块中:
执行到代码块时,作用域中通过let声明的变量b、d会放到词法环境的一个单独的区域,这个区域的变量并不影响作用域外面的变量。
在词法环境的内部,维护了一个小型栈结构,栈底时函数最外层的变量,进入一个作用域块后,就会把该作用域内部的变量压到栈顶,当作用域执行完成后,把作用域的信息从栈顶弹出。