JS闭包和作用域
执行环境定义了变量或者函数有权限访问的其他数据,决定了他们各自的行为。
- 每个函数都有自己的执行环境。当执行到一个函数时,函数的环境就会被推入到一个环境栈中,在函数执行完后,栈将其弹出, 将控制权返回给之前的执行环境
- 当代码在一个函数中执行时,会创建变量对象的一个作用域链,作用域链的作用:保证对执行环境有权访问的所有变量和函数的 有序访问。
作用域链,当执行一个函数的时候,变量的访问顺序是,现在当前的作用域上查找,没找到的话,就往上层作用域找,一直找到 window为止。作用域是在定义的时候就确定了。
(function wrap () {
var num = 10;
var getNum = function() {
console.log(num);
}
var fun1 = function () {
console.log(num)
var num = 20;
getNum();
console.log(num);
}
fun1();
})();
如上代码,打印结果分别为undefined、10、20,第一个num为undefined是因为,在fun1函数中,它会现在当前作用域(fun1)中查找num变量,在当前作用域中,有一个num变量,所以不会再往上继续查找num变量了,变量num此时还没有赋值,所以是undefined。 第二个是10,是因为在getNum函数中,在当前作用域(getNum)中查找num变量,没找到就接着往上层作用域(wrap)中查找,找到num的值为10。 第三个是20,在fun1的作用域中,num的值为20,所以是20
垃圾收集
javaScript具有自动垃圾收集机制。原理:间隔固定的时间,找出不用的变量后释放其占用的内存。 垃圾回收机制方法有标记清除和引用计数
闭包:是指有权访问另一个函数作用域中变量的函数。
闭包的特点:
- 函数嵌套函数。
- 函数内部可以引用外部的参数和变量。
- 参数和变量不会被垃圾回收机制回收
闭包的优缺点:
- 优点:避免全局变量的污染、函数封装
- 缺点:常驻内存,增加内存使用量。使用不当会很容易造成内存泄露。
var fun1 = function() {
var num = 1;
return function() {
num++;
console.log(num, this);
}
}
var fun2 = fun1();
console.log(fun2()) // 2, window
console.log(fun2()) // 3, window
通常,函数的作用域及其所有变量都会在函数执行结束后被销毁,但是由于闭包的存在,这个函数的作用域就会一直保存到闭包不存在为止。
function fun(n,o){
console.log(o);
return {
fun: function(m){
return fun(m,n);
}
};
}
var a = fun(0); // n=0, o=undefined 结果undefined
a.fun(1); // m=1, n=0, 执行fun(1,0),n=1,o=0,结果0
a.fun(2); // m=2, n=0, 执行fun(2,0),n=2,o=0,结果0
a.fun(3); // m=3, n=0, 执行fun(3,0),n=3,o=0,结果0
var b = fun(0).fun(1).fun(2).fun(3);
/**
n=0, o=undefined 结果undefined、
m=1, n=0, 执行fun(1,0),n=1,o=0,结果0、
m=2, n=1, 执行fun(2,1),n=2,o=1,结果1、
m=3, n=2, 执行fun(3,2),n=3,o=2,结果2,
最终打印undefined、0、1、2
**/
var c = fun(0).fun(1); // undefined、0
c.fun(2); // 1
c.fun(3); // 1