先来一段代码
var a = 1
function handle(){
if(true){
var a = 1
let b =2
const c = 3
}
}
handle()
然后我们来看下执行过程中,各个作用域的表现
从上面的截图我们可以看到有三种作用域,分别是
- 全局作用域Global(一般指window)
- 函数作用域Local(局部作用域)
- 块作用域Block
全局变量会挂载在window上面
局部变量在函数内部创建
块作用域是存在{}里面用let或者const创建的变量
变量的回收机制
垃圾回收器每隔一段时间就会找出那些不再使用的数据,并释放其所占用的内存空间
每次进入一个作用域时,它创建了一个变量的 环境。 就算作用域内代码已经执行完毕,这个环境与其捕获的变量依然有可能存在。
function theCityThatAlwaysSleeps() {
let getCity;
if (true) {
let city = "Seattle";
getCity = function() {
return city;
}
}
return getCity();
}
因为我们已经在city的环境里获取到了city,所以就算if语句执行结束后我们仍然可以访问它,所以一切取决于数据是否被需要
对于全局变量,垃圾回收器很难判断这些变量什么时候才不被需要,所以尽量少使用全局变量
相关的垃圾回收机制可以看:JS 从内存空间谈到垃圾回收机制
动态作用域this
上面的那些作用域我们称作词法作用域也叫做静态作用域
当然有静态就会有动态,一般我们把this叫做动态作用域,来看一段代码
window.a = 3
function test () {
console.log(this.a)
}
test.bind({ a : 2 })() //2
test() //3
上面的例子中a的值是执行的时候才知道,因为this的指向是动态的,改变this的方法有bind,apply,call,当然还有with、eval,但是我们基本不涉及到
想理解变量的创建过程可以移步看:var与let、const的区别及变量提升(函数提升)过程解析
后续:
上面我们说了闭包除外,那我们来看个例子:
function f() {
let a = 10;
return function g() {
let b = a + 1;
return b;
};
}
let g = f();
g();
此时a的变量没有被回收,看看下图:
例子中的a是闭包的变量,此时它是函数f的Closure变量