高性能javascript学习总结(3)--数据访问

在 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编程》
相关文章
相关标签/搜索