zoukankan      html  css  js  c++  java
  • 图解JavaScript执行环境、作用域、闭包

    首先我们要先知道有这三个概念,执行环境作用域链变量对象

    var numA = 0;  
    var numB = 1;
    
    function normal() {
    
        var numC = 3,
            numD = 4;
    
        return numC + numD;
    }
    
    function main() {
    
        var numE = 5;
        console.log('(1) numA = ' + numA + ' , numB = ' + numB);
        var numB = 6;
    
        return function() {
            numE += 1;
            console.log('(2) numE = ' + numE);
        }
    }
    
    normal();
    
    var result = main();  

    当开始执行上面这段js代码的时候,全局执行环境进栈,执行环境带有与之关联的变量对象,代码在环境中执行时,会创建变量对象的作用域链

    当代码执行到normal();这一行时,normal函数的执行环境被推入环境栈中。

    normal函数执行完之后,它的执行环境将被推出环境栈,当前环境回到全局执行环境。normal函数执行时所创建的活动对象(变量对象)也随之销毁(没有指针指向它,垃圾回收时会将其回收掉,释放内存).

    代码继续执行到var result = main();main函数的执行环境被推入环境栈中。

    通过上面的图也就知道了为什么main函数里面第一个console的输出结果是: "(1) numA = 0 , numB = undefined"。 numB的值为什么是undefined而不是我们在外面全局环境里面定义的var numB = 1;了。 因为变量名提升,变量对象在执行流进入函数的时候就已经创建了,标识符解析沿着作用域链一级一级查找。

    main函数的return语句里有一个匿名函数,当代码执行到return语句时,匿名函数被创建,也就是我们的闭包诞生了。

    函数被创建的同时,会创建一个作用域链,这个作用域链包含了外部函数的活动对象。注意,这里的函数的作用域链跟上面所说的环境的作用域链是不同的。函数在被创建的时候,会创建一个作用域链保存在内部的[[scope]]属性里面。函数被调用的时候,通过复制函数的[[scope]]属性中的对象构建起执行环境的作用域链,并把当前活动对象推入执行环境的作用域链的前端。 为了区分,下图用另一个颜色表示了闭包函数的作用域链。

    红色箭头,可以看到,闭包函数的作用域链其中指向了main函数的活动对象。

    当main函数执行完之后,main函数的执行环境被推出环境栈,当前环境回到全局执行环境。

    上图中可以看到,main函数执行环境已经销毁了,但是main函数的变量对象并没有像normal函数的变量对象一样销毁,由于仍然有闭包函数的作用域链的指针指向它,垃圾回收的时候释放不了内存。而闭包也因此能访问外部函数的变量对象,即使外部函数的执行环境已销毁.

    原文地址:http://zhangruojun.com/exection-scope-closure/

  • 相关阅读:
    “铁大失物帮”Alpha版使用说明
    绩效评估
    改进方案评论
    意见汇总
    对其他团队项目的意见和建议
    冲刺周期
    属于我的专属博客团队地址
    第一个冲刺周期-第三天
    第一个冲刺周期-第二天
    动手动脑与动手
  • 原文地址:https://www.cnblogs.com/zhrj000/p/6433928.html
Copyright © 2011-2022 走看看