Fork me on GitHub

理解闭包、作用域

局部作用域和垃圾回收机制

1
2
3
4
5
6
7
8
9
10
11

function a() {
var b = 12;
}
// a();
function c() {
d = 12;
}
c();
// delete window.d;
console.dir(window.d)

js的垃圾回收机制(GC:Garbage Collecation)会定期清除无用的变量,释放内存空间,首先释放的就是生命周期结束的变量,全局变量的生命周期直至浏览器卸载页面才会结束。局部变量只在函数的执行过程中存在,所以,在函数执行完之后打印b是会报错的
此处说明一下函数c内部的情况,声明变量不加var,为隐式声明,可以理解为window.d = 12;注意虽然是叫隐式声明,但是b此时并不是一个变量,而是window的一个属性,下面会专门找时间把变量和属性的区别描述清楚;

全局对象的属性和函数声明(这个属于插一曲)

1
2
3
4
5
6
7
8

var e = 123;
window.f = 1213
console.log(f)
delete window.e
delete window.f
console.dir(e)
console.log(window);

全局函数声明虽然也是挂载到window下的一个属性,但是函数声明和属性的区别是,函数声明拥有不可删除性,通过delect方法无法删除

局部作用域和闭包

1
2
3
4
5
6
7
8
9
10
11
//闭包案例
function z() {
var num = 0;
return function() {
return num++
}
}
var y = z();
console.dir(z)
console.log(y())
console.log(y())

调用一次返回值+1;
正常函数调用完之后,局部作用域内声明的变量会被清除,但是如果在局部作用域函数有函数引用变量,形成闭包环境,该变量则不会清除,就会挂载到该局部作用域;所以函数调用一次就会增加一次形成一个缓存的作用,这也是为什么闭包会容易造成内存溢出的原因;
//即使是局部作用域的函数未清除,全局作用域仍然无法获取该变量;所以这也是自执行函数IFEE能够形成自己独立区域的原因,防止变量污染;

块级作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//所谓的块级作用域就是{}
{
var aa = 1
}
console.log(aa) //1;

//使用var声明变量没有块级作用域,常见的还有for循环中的变量i值
{
let bb = 1;
console.log(bb) //1;
}
console.log(bb) //: bb is not defined

// 使用es6的let和const可以生成一个块级作用域,所以之前的自调用函数,可以使用{}代替