javascript 用局部变量来代替全局变量第1/2页

为什么要这么做?有什么根据么?不这么做,对性能到底能带来多大的损失?本文就来探讨这些问题的答案,从根本上了解变量的读写性能都和哪些因素有关。
著作权声明 
       本文译自 Nicholas C. Zakas 于2009年2月10日在个人网站上发表的《JavaScript Variable Performance》。原文是唯一的正式版,本文是经过原作者(Nicholas C. Zakas)授权的简体中文翻译版(Simplified Chinese Translation)。译者(明达)在翻译的准确性上做了大量的努力,并承诺译文的内容完全忠于原文,但可能还是包含疏漏和不妥之处,欢迎大家指正。译注的内容是非正式的,仅代表译者个人观点。

以下是对原文的翻译
       在如何提高JavaScript性能这个问题上,大家最常听到的建议应该就是尽量使用局部变量(local variables)来代替全局变量(global variables)。在我从事Web开发工作的九年时间里,这条建议始终萦绕在我的耳边,并且从来没有质疑过,而这条建议的基础,则来自于 JavaScript处理作用域(scoping)和标识符解析(identifier resolution)的方法。

首先我们要明确,函数在JavaScript中具体表现为对象,创建一个函数的过程,其实也就是创建一个对象的过程。每个函数对象都有一个叫做 [[Scope]]的内部属性,这个内部属性包含创建函数时的作用域信息。实际上,[[Scope]]属性对应的是一个对象(Variable Objects)列表,列表中的对象是可以从函数内部访问的。比如说我们建立一个全局函数A,那么A的[[Scope]]内部属性中只包含一个全局对象(Global Object),而如果我们在A中创建一个新的函数B,那么B的[[Scope]]属性中就包含两个对象,函数A的Activation Object对象在前面,全局对象(Global Object)排在后面。

当一个函数被执行的时候,会自动创建一个可以执行的对象(Execution Object),并同时绑定一个作用域链(Scope Chain)。作用域链会通过下面两个步骤来建立,用于进行标识符解析。

  1. 首先将函数对象[[Scope]]内部属性中的对象,按顺序复制到作用域链中。
  2. 其次,在函数执行时,会创建一个新的Activation Object对象,这个对象中包含了this、参数(arguments)、局部变量(包括命名的参数)的定义,这个Activation Object对象会被置于作用域链的最前面。

在执行JavaScript代码的过程中,当遇到一个标识符,就会根据标识符的名称,在执行上下文(Execution Context)的作用域链中进行搜索。从作用域链的第一个对象(该函数的Activation Object对象)开始,如果没有找到,就搜索作用域链中的下一个对象,如此往复,直到找到了标识符的定义。如果在搜索完作用域中的最后一个对象,也就是全局对象(Global Object)以后也没有找到,则会抛出一个错误,提示用户该变量未定义(undefined)。这是在ECMA-262标准中描述的函数执行模型和标识符解析(Identifier Resolution)的过程,事实证明,大部分的JavaScript引擎确实也是这样实现的。需要注意的是,ECMA-262并没有强制要求采用这种结构,只是对这部分功能加以描述而已。

了解标识符解析(Identifier Resolution)的过程以后,我们就能明白为什么局部变量的解析速度要比其他作用域的变量快,主要是由于搜索过程被大幅缩短了。但是,具体会快多少呢?为了回答这个问题,我模拟了一系列的测试,来测试不同作用域深度中变量的性能。

第一个测试是向一个变量中写入一个最简单的值(这里使用字面量的数值1),结果如下图显示,很有趣:

       从结果中不难看出,当标识符解析的过程需要进行深度搜索时,会伴随性能损失,而且性能损失的程度会随着标识符深度的增加而递增。意料之中的是,Internet Explorer表现的是最差的(但公平的说,IE 8还是有一些改善的)。值得注意的是,这里有一些例外情况,Google Chrome和最新的WebKit午夜版在访问变量的时间保持得很稳定,不会随着作用域深度的递增而增长。当然,这应该归功于它们所使用的下一代 JavaScript引擎,V8和SquirrelFish。这些引擎在执行代码时进行了优化,而且很明显,这些优化使访问变量的速度比以往更快。 Opera表现的也很不错,比IE、Firefox和当前版本的Safari要快的多,但比基于V8和Squirrelfish的浏览器要慢。 Firefox 3.1 Beta 2的表现有点出人意料,对于局部变量执行的效率非常高,但随着作用域层数的增加,效率便大打折扣。需要注意的是,我这里使用的都是默认设置,也就是说 Firefox是没有开启Trace功能的。

当前1/2页 12下一页阅读全文

(0)

相关推荐

  • javascript中局部变量和全局变量的区别详解

    javascript有两种变量:局部变量和全局变量.当然,我们这篇文章是帮助大家真正的区别这两种变量. 首先,局部变量是指只能在本变量声明的函数内部调用.全局变量时整个代码中都可以调用的变量.当然,单单从字面上理解肯定是不清楚的,下面我详细的介绍下: 大家都知道,变量是需要用var关键字声明的.但是javascript中也可以隐式的使用变量,就是不用声明,直接使用.而且,千万注意,javascript把隐式声明的变量总是当成全局变量来使用的. 例如: 复制代码 代码如下: function my

  • 浅谈JavaScript的全局变量与局部变量

    一.JavaScript scope 的划分标准是function函数块,不是以 if.while.for来划分的 <script> function f1(){ alert("before for scope:"+i); //i未赋值(并不是没有声明!使用未声明变量或函数会导致致命错误从而中断脚本执行) //此时i值为undefined for(var i=0; i<3;i++){ alert("in for scope:"+i);} //i的值

  • Javascript学习之谈谈JS的全局变量跟局部变量(推荐)

    今天公司一个实习小妹子问我两段JS代码的区别: 代码一: <script type="text/javascript"> var a = "Hello"; function test(){ var a; alert(a); a = "World"; alert(a); } </script> 代码二: <script type="text/javascript"> var a = "

  • JS全局变量和局部变量最新解析

    就是这种盲目无原理依据的研究测试弄晕了我, 有必要这么做吗? 其实理解了原理就没必要搞这么多一个一个的试, 然后得出规律, ECMAScript规则都已经定义好了. var的规则是: 使用var声明变量就是内部变量, 否则就是先调用全局变量, 不管多少层函数. this的规则是: method函数里的this永远指向自身, 普通函数的this永远指向DOMWindow. // GodDamnTest1 function Foo() { var a = 123; // 局部变量, 所有子函数的全局

  • javascript 用局部变量来代替全局变量第1/2页

    为什么要这么做?有什么根据么?不这么做,对性能到底能带来多大的损失?本文就来探讨这些问题的答案,从根本上了解变量的读写性能都和哪些因素有关. 著作权声明        本文译自 Nicholas C. Zakas 于2009年2月10日在个人网站上发表的<JavaScript Variable Performance>.原文是唯一的正式版,本文是经过原作者(Nicholas C. Zakas)授权的简体中文翻译版(Simplified Chinese Translation).译者(明达)在翻

  • JavaScript把局部变量变成全局变量的方法

    首先我们要知道函数的自调用 函数的自调用--自调用函数 一次性的函数--声明的同时,直接调用了 例如: (function () { console.log("函数"); })(); 我们会看到浏览器直接打印 函数 两个字 页面加载后.这个自调用函数的代码就执行完了 使用形式 (function (形参) { })(实参); 注意 自调用构造函数的方式,分号一定要加上 那么如何把局部变量变成全局变量? 把局部变量给window就可以了 (function (win) { var num

  • 浅析JavaScript预编译和暗示全局变量

    1. 暗示全局变量 未声明的变量称为暗示全局变量. var a = 1; //函数体外声明的变量称为全局变量 b = 2; // 无论函数体外或函数体内未声明的变量都称为暗示全局变量 function fn() { var c = 3; //函数体内声明的变量称为局部变量 d = 4; // 暗示全局变量 } fn(); // 若不执行函数,则不会进行函数预编译,d 就不会提升为全局变量 console.log(c); // error: c is not defined console.log

  • javascript(jquery)利用函数修改全局变量的代码

    我是将当前页用一个全局变量存储.同时在"最后一页"链接里单击方法调用一个函数自动去修改页数为最后一页,然后再调用载入评论的方法. 可是我发现点击"最后一页"第一次的时候系统没反应,再点击一次就抓去最后一页的资料了! 要说全局变量没改,应该是改了,就仿佛改了页数而载入评论的方法失效了一样. 代码如下: 复制代码 代码如下: var page = 1; //初始化页数为第一页 var str = ""; $(document).ready(funct

  • 不错的JavaScript面向对象的简单入门介绍第1/2页

    1) 如何创建对象: 1. 使用constructor,例如: var obj = new Object() // var 可以省略 var obj = new Date() 2. 使用对象字面值(object literals),例如: 程序代码 var obj = "123" // 创建一个String对象 var obj = /^abc$/ //创建一个RegExp对象 更加复杂的情况是,我们可以直接生成一个自定义的只有属性的对象: 程序代码 var obj = { name:&

  • 魔鬼字典 JavaScript 笔记 代码比较多乱第1/3页

    //2005中ctrl+J 有可能出提示 //文本编辑出注释的快捷键 名词解释: { //Java: 爪哇语言, 在因特网世界范围的 web 网页运转的以网络为基础的编程语言 (计算机用语) //Script : 手稿, 剧本, 手迹 //cs结构: 客户端应用程序,用户需要下载客户端,例如QQ //BS结构: 浏览器应用程序,具有远程服务器,例如网页 脚本语言:解释性语言,不进行编译,只在运行至相应代码时进行解释 } 完整的JavaScript组成 { 核心:ECMAScript 文档对象模型

  • JavaScript的学习入门整理篇第1/3页

    <html><head><meta http-equiv="Content-Type" content="text/html;charset=gb2312"><title>Document.writeln()方法</title><script language="javascript">function createsummary(){     win2=open("

  • 浅谈javascript函数劫持[转自xfocus]第1/3页

    一.概述 javascript函数劫持,也就是老外提到的javascript hijacking技术.最早还是和剑心同学讨论问题时偶然看到的一段代码,大概这样写的: window.alert = function(s) {}; 觉得这种用法很巧妙新颖,和API Hook异曲同工,索性称之为javascript function hook,也就是函数劫持.通过替换js函数的实现来达到劫持这个函数调用的目的,一个完整的hook alert函数例子如下: <!--1.htm--> 复制代码 代码如下

  • JavaScript 函数式编程实践(来自IBM)第1/3页

    函数式编程简介 说到函数式编程,人们的第一印象往往是其学院派,晦涩难懂,大概只有那些蓬头散发,不修边幅,甚至有些神经质的大学教授们才会用的编程方式.这可能在历史上的某个阶段的确如此,但是近来函数式编程已经在实际应用中发挥着巨大作用了,而更有越来越多的语言不断的加入诸如 闭包,匿名函数等的支持,从某种程度上来讲,函数式编程正在逐步"同化"命令式编程. 函数式编程思想的源头可以追溯到 20 世纪 30 年代,数学家阿隆左 . 丘奇在进行一项关于问题的可计算性的研究,也就是后来的 lambd

随机推荐