JavaScript 高性能编程 —— Data Access 数据访问

本文探讨了JavaScript中数据访问的性能,强调了直接量和局部变量优于数组项和对象成员。介绍了作用域链和标识符解析对性能的影响,指出避免使用with表达式和过多的嵌套成员可以提高代码效率。同时,文章提到了闭包的内存和性能成本,建议谨慎使用。通过对对象成员的理解,特别是原型链和原形,展示了如何通过缓存对象成员值来优化性能。
摘要由CSDN通过智能技术生成

        经典计算机科学的一个问题是确定数据应当存放在什么地方,以实现最佳的读写效率。数据存储在哪里, 关系到代码运行期间数据被检索到的速度。在 JavaScript 中,此问题相对简单,因为数据存储只有少量方 式可供选择。正如其他语言那样,数据存储位置关系到访问速度。

在 JavaScript 中有四种基本的数据访问 位置:

  • 直接量 ,直接量仅仅代表自己,而不存储于特定位置。 JavaScript 的直接量包括:字符串,数字,布尔值,对象, 数组,函数,正则表达式,具有特殊意义的空值,以及未定义。
  • 变量,开发人员使用 var 关键字创建用于存储数据值。
  • 数组项,具有数字索引,存储一个 JavaScript 数组对象。
  • 对象成员 ,具有字符串索引,存储一个 JavaScript 对象。

        每一种数据存储位置都具有特定的读写操作负担。大多数情况下,对一个直接量和一个局部变量数据访 问的性能差异是微不足道的。访问数组项和对象成员的代价要高一些,具体高多少,很大程度上依赖于浏 览器。

        图 2-1 显示了不同浏览器中,分别对这四种数据类型进行 200'000 次操作所用的时间。

        老一些的浏览器使用传统的 JavaScript 引擎,如 Firefox 3,Internet Explorer 和 Safari 3.2,它们比优化后 的 JavaScript 引擎耗费太多时间。

        总的来说,直接量和局部变量的访问速度要快于数组项和对象成员的访 问速度。只有一个例外,Firefox 3,优化过数组项访问所以非常快。即使如此,一般的建议是,如果关心 运行速度,那么尽量使用直接量和局部变量,限制数组项和对象成员的使用。为此,有几种模式来查看、 避免并优化你的代码。

5913a9614f7d47449f1cb030a2bf4cb5.png

图 2-1 对不同数据类型进行 200'000 次读操作所用的时间

Managing Scope 管理作用域

        作用域概念是理解 JavaScript 的关键,不仅从性能的角度,而且从功能的角度。作用域对 JavaScript 有 许多影响,从确定哪些变量可以被函数访问,到确定 this 的值。JavaScript 作用域也关系到性能,但是要理 解速度与作用域的关系,首先要理解作用域的工作原理。

Scope Chains and Identifier Resolution 作用域链和标识符解析

        每一个 JavaScript 函数都被表示为对象。进一步说,它是一个函数实例。函数对象正如其他对象那样, 拥有你可以编程访问的属性,和一系列不能被程序访问,仅供 JavaScript 引擎使用的内部属性。其中一个 内部属性是[[Scope]],由 ECMA-262 标准第三版定义。

        内部[[Scope]]属性包含一个函数被创建的作用域中对象的集合。此集合被称为函数的作用域链,它决定 哪些数据可由函数访问。此函数作用域链中的每个对象被称为一个可变对象,每个可变对象都以“键值对”的形式存在。当一个函数创建后,它的作用域链被填充以对象,这些对象代表创建此函数的环境中可访问 的数据。例如下面这个全局函数:

function add(num1, num2){ 
 var sum = num1 + num2; 
 return sum; 
} 

        当 add()函数创建后,它的作用域链中填入一个单独的可变对象,此全局对象代表了所有全局范围定义 的变量。此全局对象包含诸如窗口、浏览器和文档之类的访问接口。图 2-2 指出它们之间的关系(注意: 此图中只画出全局变量中很少的一部分,其他部分还很多)。

ef3596a4c4244de2a91544789ac2afa0.png

图 2-2 add()函数的作用域链

add 函数的作用域链将会在运行时用到。假设运行下面的代码:

var total = add(5, 10);

        运行此 add 函数时建立一个内部对象,称作“运行期上下文”。一个运行期上下文定义了一个函数运行时 的环境。对函数的每次运行而言,每个运行期上下文都是独一的,所以多次调用同一个函数就会导致多次 创建运行期上下文。当函数执行完毕,运行期上下文就被销毁。

        一个运行期上下文有它自己的作用域链,用于标识符解析。当运行期上下文被创建时,它的作用域链被 初始化,连同运行函数的[[Scope]]属性中所包含的对象。这些值按照它们出现在函数中的顺序,被复制到 运行期上下文的作用域链中。这项工作一旦完成,一个被称作“激活对象”的新对象就为运行期上下文创建 好了。此激活对象作为函数执行期的一个可变对象,包含访问所有局部变量,命名参数,参数集合,和 this 的接口。然后,此对象被推入作用域链的前端。当作用域链被销毁时,激活对象也一同销毁。图 2-3 显示 了前面实例代码所对应的运行期上下文和它的作用域链。

6777d34d3b4947c8b62fe5fc5e809474.png

 图 2-3 运行 add()时的作用域链

 

        在函数运行过程中,每遇到一个变量,标识符识别过程要决定从哪里获得或者存储数据。此过程搜索运 行期上下文的作用域链,查找同名的标识符。搜索工作从运行函数的激活目标之作用域链的前端开始。如 果找到了,那么就使用这个具有指定标识符的变量;如果没找到,搜索工作将进入作用域链的下一个对象。 此过程持续运行,直到标识符被找到,或者没有更多对象可用于搜索,这种情况下标识符将被认为是未定 义的。函数运行时每个标识符都要经过这样的搜索过程,例如前面的例子中,函数访问 sum,num1,num2 时都会产生这样的搜索过程。正是这种搜索过程影响了性能。

Identifier Resolution Performance 标识符识别性能

        标识符识别不是免费的&#x

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值