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固有的特性——执行上下文,能够模拟面向对象中的私有变量这种封装方式。

 

 

posted @ 2013-10-12 19:31  天边彩云  阅读(1504)  评论(2编辑  收藏  举报