js闭包与执行上下文

86 阅读2分钟

闭包

function f1() {
    var n = "Mozilla";
    function f2() {
        alert(n);}//f2可以访问f1中的n
    return f2;//把f2作为返回值
}
var m = f1();
m();//就可以在f1外读取f1内部变量

描述

  • 闭包可以让你从内部函数访问外部函数作用域。
  • 子级可以向父级查找变量,逐级查找,直到找到,并且闭包能让函数的内部变量(局部变量)始终保存在内存中。
  • 一个函数在定义时和它周围状态的引用捆绑在一起,函数可以记住并访问所在的词法作用域
  • 内部函数的作用域链仍然保存对外部函数活动对象引用

执行上下文

上下文有三种:

  • 全局上下文

  • 函数上下文==>arguments

    函数执行上下文在函数调用时创建,若多次调用则都会创建一个新的上下文

    执行上下文栈(调用栈,执行栈)储存代码执行期间创建的所有上下文,有LIFO(后进先出)特性

  • eval上下文

上下文中有三个属性:

  1. VO(变量对象),激活后为(AO)活动对象
  2. 作用域链
  3. this
for(var i=0;i<5;i++){
    setTimeout(function(){
        console.log(i++);
    },4000);//5 6 7 8 9
}
console.log(i);//5
//setTimeout有执行队列
for(var i=0;i<5;i++){
    (function(){
        console.log(i++);
    })();//0 2 4
}
console.log(i);//6
for(var i=0;i<5;i++){
    (function(x){
        setTimeout(function(){
            console.log(x++);
        },4000);
    })(i);//0 1 2 3 4
}
console.log(i);//5

setTimeout是异步宏任务,不会直接执行,而会被放入任务队列里面,等待所有的同步代码执行完毕后才会执行。

为什么会一下输出56789,而不是每隔4秒输出,是因为在同步代码中通过for循环在极短的时间内就将5个异步任务放入了任务队列,他们几乎同时开始计时。所以隔了4秒后,所有的任务几乎同时完成。完成的任务会一个一个的从任务队列中取出,来到主线程中(也就是同步任务执行的线程)。

优点

方便调用上下文中声明的局部变量

可以在一个函数中创建函数,避免传参问题

闭包的危害

内部函数被保留到外部,导致原有的作用域链不释放,造成内存泄露

尤其在闭包中有DOM时和大量使用闭包时内存消耗很大

所以能用this就不用闭包