在 JavaScript 中,数据存储位置可以对代码整体性能产生重要影响。有四种数据访问类型:直接量,变量,数组项,对象成员。
        直接量仅仅代表自己,而不存储于特定位置。 JavaScript 的直接量包括:字符串,数字,布尔值,对象,数组,函数,正则表达式,具有特殊意义的空值,以及未定义。 
        变量是指开发人员使用 var关键字创建用于存储数据值。 
        数组现是指具有数字索引,存储一个 JavaScript数组对象。 
        对象成员具有字符串索引,存储一个 JavaScript 对象。 
它们有不同的性能考虑。 直接量和局部变量访问速度非常快,数组项和对象成员需要更长时间。 局部变量比域外变量快,因为它位于作用域链的第一个对象中。变量在作用域链中的位置越深,访问所需的时间就越长。全局变量总是最慢的,因为它们总是位于作用域链的最后一环。
        作用域链和标识符解析
       每一个 JavaScript 函数都被表示为对象。进一步说,它是一个函数实例。函数对象正如其他对象那样,拥有你可以编程访问的属性,和一系列不能被程序访问,仅供 JavaScript 引擎使用的内部属性。其中一个内部属性是[[Scope]],由ECMA-262 标准第三版定义。 
       内部[[Scope]]属性包含一个函数被创建的作用域中对象的集合。此集合被称为函数的作用域链,它决定哪些数据可由函数访问。此函数作用域链中的每个对象被称为一个可变对象,每个可变对象都以“键值对”的形式存在。当一个函数创建后,它的作用域链被填充以对象,这些对象代表创建此函数的环境中可访问的数据。例如下面这个全局函数: 
function add(num1, num2){
var sum = num1 + num2;
return sum;
}
    当 add()函数创建后,它的作用域链中填入一个单独的可变对象,此全局对象代表了所有全局范围定义的变量。此全局对象包含诸如窗口、浏览器和文档之类的访问接口。图指出它们之间的关系(注意:此图中只画出全局变量中很少的一部分,其他部分还很多)。 
   
     运行此 add 函数时建立一个内部对象,称作“运行期上下文”。一个运行期上下文定义了一个函数运行时的环境。对函数的每次运行而言,每个运行期上下文都是独一的,所以多次调用同一个函数就会导致多次创建运行期上下文。当函数执行完毕,运行期上下文就被销毁。 
     一个运行期上下文有它自己的作用域链,用于标识符解析。当运行期上下文被创建时,它的作用域链被初始化,连同运行函数的[[Scope]]属性中所包含的对象。这些值按照它们出现在函数中的顺序,被复制到运行期上下文的作用域链中。这项工作一旦完成,一个被称作“激活对象”的新对象就为运行期上下文创建好了。此激活对象作为函数执行期的一个可变对象,包含访问所有局部变量,命名参数,参数集合,和 this的接口。然后,此对象被推入作用域链的前端。当作用域链被销毁时,激活对象也一同销毁。显示了前面实例代码所对应的运行期上下文和它的作用域链。 
     在函数运行过程中,每遇到一个变量,标识符识别过程要决定从哪里获得或者存储数据。此过程搜索运行期上下文的作用域链,查找同名的标识符。搜索工作从运行函数的激活目标之作用域链的前端开始。如果找到了,那么就使用这个具有指定标识符的变量;如果没找到,搜索工作将进入作用域链的下一个对象。此过程持续运行,直到标识符被找到,或者没有更多对象可用于搜索,这种情况下标识符将被认为是未定义的。函数运行时每个标识符都要经过这样的搜索过程,例如前面的例子中,函数访问 sum,num1,num2时都会产生这样的搜索过程。正是这种搜索过程影响了性能。 
     标识符识别不是免费的, 事实上没有哪种电脑操作可以不产生性能开销。 在运行期上下文的作用域链中,一个标识符所处的位置越深,它的读写速度就越慢。所以,函数中局部变量的访问速度总是最快的,而全局变量通常是最慢的(优化的 JavaScript 引擎在某些情况下可以改变这种状况)。全局变量总是处于运行期上下文作用域链的最后一个位置,所以总是最远才能触及的。
         一般来说,一个运行期上下文的作用域链不会被改变。但是,有两种表达式可以在运行时临时改变运行期上下文作用域链。第一个是 with表达式。当代码流执行到一个 with 表达式时,运行期上下文的作用域链被临时改变了。一个新的可变对象将被创建,它包含指定对象的所有属性。此对象被插入到作用域链的前端,意味着现在函数的所有局部变量都被推入第二个作用域链对象中,所以访问代价更高了。 第二个是try-catch 表达式。当 try块发生错误时,程序流程自动转入 catch 块,并将异常对象推入作用域链前端的一个可变对象中。在 catch 块中,函数的所有局部变量现在被放在第二个作用域链对象中。所以,避免使用 with 表达式, 因为它改变了运行期上下文的作用域链。 而且应当小心对待 try-catch 表达式的 catch子句,因为它具有同样效果。
        嵌套对象成员会造成重大性能影响, 一个属性或方法在原形链中的位置越深,访问它的速度就越慢。 如果可能的话请避免使用它们。更确切地说,你应当小心地,只在必要情况下使用对象成员。如果在同一个函数中你要多次读取同一个对象属性,最好将它存入一个局部变量。以局部变量替代属性,避免多余的属性查找带来性能开销。在处理嵌套对象成员时这点特别重要,它们会对运行速度产生难以置信的影响。 
    
        一般来说,你可以通过这种方法提高 JavaScript代码的性能:将经常使用的对象成员,数组项,和域外变量存入局部变量中。然后,访问局部变量的速度会快于那些原始变量。
ps:以上内容总结于《高性能javascript编程》

高性能javascript学习总结(3)--数据访问的更多相关文章

  1. 高性能javascript学习笔记系列(2)-数据存取

    参考 高性能javascript Tom大叔深入理解javascript系列 相关概念 1.执行上下文   当控制器转到ecmascript可执行代码的时候,就会进入一个执行上下文,执行上下文是以堆栈 ...

  2. 高性能javascript学习笔记系列(6) -ajax

    参考 高性能javascript javascript高级程序设计 ajax基础  ajax技术的核心是XMLHttpRequest对象(XHR),通过XHR我们就可以实现无需刷新页面就能从服务器端读 ...

  3. 高性能javascript学习总结(2)--DOM编程

    我们知道,对DOM的操作都是非常的耗性能的,那么为什么会耗性能呢?      文档对象模型(DOM)是一个独立于语言的,使用 XML和 HTML 文档操作的应用程序接口(API).在浏览器中,主要与 ...

  4. 高性能javascript学习笔记系列(5) -快速响应的用户界面和编程实践

    参考高性能javascript 理解浏览器UI线程  用于执行javascript和更新用户界面的进程通常被称为浏览器UI线程  UI线程的工作机制可以理解为一个简单的队列系统,队列中的任务按顺序执行 ...

  5. 高性能javascript学习笔记系列(3) -DOM编程

    参考 高性能javascript 文档对象模型(DOM)是独立于语言的,用于操作XML和HTML文档的程序接口API,在浏览器中主要通过DOM提供的API与HTML进行交互,浏览器通常会把DOM和ja ...

  6. 高性能javascript 学习笔记(1)

    加载和运行 管理浏览器中的javascript代码是个棘手的问题,因为代码运行阻塞了其他浏览器处理过程,诸如用户绘制,每次遇到<script>标签,页面必须停下来等待代码下载(如果是外部的 ...

  7. 高性能javascript学习笔记系列(4) -算法和流程控制

    参考高性能javascript for in 循环  使用它可以遍历对象的属性名,但是每次的操作都会搜索实例或者原型的属性 导致使用for in 进行遍历会产生更多的开销 书中提到不要使用for in ...

  8. 高性能javascript学习笔记系列(1) -js的加载和执行

    这篇笔记的内容主要涉及js的脚本位置,如何加载js脚本和脚本文件执行的问题,按照自己的理解结合高性能JavaScript整理出来的 javascript是解释性代码,解释性代码需要经历转化成计算机指令 ...

  9. Spring.Net学习笔记(二)-数据访问器

    Spring对ADO.NET也提供了支持,依赖与程序集Spring.Data.dll IDbProvider IDbProvider定义了数据访问提供器的基础,配置如下 <?xml versio ...

随机推荐

  1. javascript判断是否为数组 面试题

    1.方法 instanceof:多框架下有问题(看示例代码). Object.prototype.toString.call():兼容性很好 Array.isArray: IE9+以上 constru ...

  2. [LeetCode] Restore IP Address [28]

    题目 Given a string containing only digits, restore it by returning all possible valid IP address comb ...

  3. 分组password算法

    代换,S盒.扩散和混淆,这些概念构成了分组password学的基础. 假设明文和密文的分组长度都为n比特,则明文的每个分组都有2n个可能的取值; 代换: 为使加密运算可逆(即解密运算可行),明文的每个 ...

  4. [译] ContentEditable 那些好的、坏的和坑

    译者注 我的上一篇译文 “[译] 通过 contentEditable 属性创建一个所见即所得的编辑器” 的原文 “Create a WYSIWYG Editor With the contentEd ...

  5. 使用ALAssetsLibrary读取所有照片

    一. ALAssetsLibrary 介绍 ALAssetsLibrary 提供了访问iOS设备下”照片”应用下所有照片和视频的接口: 从 ALAssetsLibrary 中可读取所有的相册数据,即  ...

  6. Hibernate学习之类级别注解

    © 版权声明:本文为博主原创文章,转载请注明出处 类级别注解: 1. @Entity 实体:表示映射实体类,使用@Entity时必须指定实体类的主键属性 @Entity(name="&quo ...

  7. angularjs2中的非父子组件的通信

    AngualrJs2官方方法是以@Input,@Output来实现组件间的相互传值,而且组件之间必须父子关系,下面给大家提供一个简单的方法,实现组件间的传值,不仅仅是父子组件,跨模块的组件也可以实现传 ...

  8. python selenium2示例 - email发送

    前言 在进行日常的自动化测试实践中,我们总是需要将测试过程中的记录.结果等等等相关信息通过自动的手段发送给相关人员.python的smtplib.email模块为我们提供了很好的email发送等功能的 ...

  9. cordova ios升级插件

    org.ssgroup.sope.cordova.upgrade 支持强制升级与选择升级 插件已经开源在https://github.com/shenshouer/org.ssgroup.sope.c ...

  10. python实现身份证识别

    github: 人脸联合语音身份认证:https://github.com/tsstss123/faceUnionVoiceRecognition 身份证识别简易版:https://github.co ...