• Javascript本质第二篇:执行上下文


    在上一篇文章《Javascript本质第一篇:核心概念》中,对Javascript执行上下文做了解释,但是这些都是基于Javascript标准中对执行上下文的定义,也就是说理论上的东西,本文将在Google Chrome中通过实际代码来展示Javascript的执行上下文。

    1. Javascritp运行时内存监控

    Google Chrome的开发人员工具包含了Javascript性能监控工具,通过这个工具可以查看Javascript运行时内存占用情况、监控CPU消耗、查找内存泄漏等。

    F12打开Chrome的开发人员工具,点击“Profiles”选项卡,选择“Take Heap Snapshot”,点击“Take Snapshot”按钮(或者点击下面黑色的实心圆)就可以拍摄一个当前内存的快照。

    在快照中可以浏览当前Javascript运行时中包含的所有对象的信息和对象之间的引用关系,这些对象包括用户创建的对象和系统创建的对象。

    由于一个快照中包含的对象数量往往非常大,多数都是页面初始化时创建的页面对象和用户不可访问的系统对象,不便于查找。为此,可以拍摄两个快照,Chrome能够计算出在两个快照之间创建的对象,通过分析新增对象,可以直观的看到代码运行时内存分配和占用情况。

    2. 执行上下文

    创建一段包含两级嵌套执行上下文的演示代码 :

     1         fun = (function () {
     2             var a = (Math.random() * 10000).toFixed();
     3             return (function () {
     4                 var b = (Math.random() * 10000).toFixed();
     5                 var f = function () {
     6                     var c = (Math.random() * 10000).toFixed();
     7                     return a + " - " + b + " - " + c;
     8                 };
     9                 return f;
    10             })
    11         })();
    12         a = fun();
    13         b = fun();

    先在console先运行一遍这段代码,拍摄一个内存快照Snapshot 1。

    再在console运行一遍这段代码,拍摄一个内存快照Snapshot 2。

    (如果直接上来拍摄内存快照Snapshot 1,运行代码再拍摄Snapshot 2,由于代码第一次运行,会产生大量系统对象,不便于对象查找。)

    在Profiles标签页的下方选择Objects allocated between Snapshots 1 and 2。

    这时对象窗口就按构造函数分类列出了所有对象。

    找到(closure)行,展开,查找被高亮的三行,这三行就对应fun、a、b这三个函数,也就是三个闭包。

    ...

    形如@63185是对象唯一标识。

    context就是执行上下文。

    previous表示当前执行上下文的上级执行上下文。

    可以看到,a和b这两个函数所在的执行上下文的上级执行上下文与fun所在的执行上下文相同,都是标识为@63187的对象。

    三个函数,三个闭包,三个执行上下文。函数内部的变量a和b都位于context中。

    下面是代码运行结果截图,在之Snapshot 2后又分别运行了a和b三次,以显示输出的结果。

     可以看到,7780、 5523 和 8360这三个变量值出现在了前面的对象截图中,最后一个值是每次调用时实时生成。

    下面的代码演示了修改执行上下文中变量的值:

     1         fun = (function () {
     2             var a = (Math.random() * 10000).toFixed();
     3             var a_1 = "data";
     4             return (function () {
     5                 var b = (Math.random() * 10000).toFixed();
     6                 var obj = {
     7                     getB: function () {
     8                         return b;
     9                     },
    10                     setB: function () {
    11                         b = (Math.random() * 10000).toFixed();
    12                     },
    13                     getA: function () {
    14                         return a;
    15                     },
    16                     setA: function () {
    17                         a = (Math.random() * 10000).toFixed();
    18                     },
    19                     show: function () {
    20                         var c = (Math.random() * 10000).toFixed();
    21                         return a + " - " + b + " - " + c;
    22                     }
    23 
    24                 };
    25                 return obj;
    26             })
    27         })();
    28         a = fun();
    29         b = fun();

     运行结果如下:

    如果你在Profiles中监视新fun函数所在的执行上下文的时候,会发现a_1这个变量没有出现在执行上下文中,应该是a_1没有在内部函数中被使用,chrome将它优化掉了。

    3. 结论

    闭包是Javascript的一个重要编程模式,它利用了Javascript固有的特性——执行上下文,能够模拟面向对象中的私有变量这种封装方式。

  • 相关阅读:
    ORACLE SQL性能优化系列 (十一)
    ORACLE SQL性能优化系列 (七)
    ORACLE SQL性能优化系列 (十三)
    Oracle绑定变量
    ORACLE SQL性能优化系列 (九)
    C#中&与&&的区别
    简单代码生成器原理剖析
    C#线程系列讲座(1):BeginInvoke和EndInvoke方法
    ClearCanvas DICOM 开发系列 一
    C# winform 获取当前路径
  • 原文地址:https://www.cnblogs.com/ioexception/p/essential_Javascript_execute_context.html
Copyright © 2020-2023  润新知