JavaScript 高效运行代码分析(2)

如果可能,应在脚本中不频繁被调用的地方进行异常处理,或通过检查某种动作是否被支持来避免使用。下面的例子中,如果所需的属性不存在,将在循环语句中抛出许多异常:

复制代码 代码如下:

var oProperties = ['first','second','third',...,'nth'], i; for( i = 0; i < oProperties.length; i++ ) { try { test[oProperties[i]].someproperty = somevalue; } catch(e) { ... } } 很多情况下,可把 try-catch-finally 结构移到循环外部。这样做稍微改变了程序语义,因为如果抛出异常,将停止整个循环:var oProperties = ['first','second','third',...,'nth'], i; try { for( i = 0; i < oProperties.length; i++ ) { test[oProperties[i]].someproperty = somevalue; } } catch(e) { ... }

有时可用属性检测或其他检测代替 try-catch-finally 结构:

[code]var oProperties = ['first','second','third',...,'nth'], i; for( i = 0; i < oProperties.length; i++ ) { if( test[oProperties[i]] ) { test[oProperties[i]].someproperty = somevalue; } }

分隔 eval 和 with

因为 eval 和 with 结构严重影响性能,应该尽量避免使用这些结构。但如不得不使用时, 避免在频繁被调用的函数中或循环中使用这些结构。最好将这些结构放在只运行一次,或少量几次的代码中,并不要将其放在对性能要求较高的代码中。

如果可能,尽量将这些结构和其他代码分隔开,这样他们就不会影响脚本性能。如将其放在顶级函数中,或只执行一次然后保存运行结果,避免再次使用。

try-catch-finally 结构在一些浏览器中也会影响性能,包括 Opera ,因此最好也将其分隔。

避免使用全局变量

全局变量使用简单,因此很容易禁不住诱惑在脚本中使用全局变量。但有时全局变量也会影响脚本性能。

首先,如果函数或其他作用域内引用了全局变量,则脚本引擎不得不一级一级查看作用域直到搜索到全局作用域。查询本地作用域变量更快。

其次,全局变量将始终存在在脚本生命周期中。而本地变量在本地作用域结束后就将被销毁,其所使用的内存也会被垃圾收集器回收。

最后,window 对象也共享全局作用域,也就是说本质上是两个作用域而不是一个。使用全局变量不能像使用本地变量那样使用前缀,因此脚本引擎要花更多时间查找全局变量。

也可在全局作用域中创建全局函数。函数中可以调用其他函数,随着函数调用级数增加,脚本引擎需要花更多时间才能找到全局变量以找到全局变量。

考虑下面的简单例子,i 和 s 是全局作用域且函数使用这两个全局变量:

复制代码 代码如下:

var i, s = ''; function testfunction() { for( i = 0; i < 20; i++ ) { s += i; } } testfunction();

下面的函数效率更高。在大多数浏览器中,包括 Opera 9、最新版 Internet Explorer, Firefox, Konqueror 和 Safari,后者执行速度比上面代码快30%。

function testfunction() { var i, s = ''; for( i = 0; i < 20; i++ ) { s += i; } } testfunction(); 注意隐式对象转换

Literal,如字符串、数字和布尔值在 ECMAScript 中有两种表示方法。 每个类型都可以创建变量值或对象。如 var oString = 'some content';, 创建了字符串值,而 var oString = new String('some content');创建了字符串对象。

所有的属性和方法都定义在 string 对象中,而不是 string 值中。每次使用 string 值的方法或属性,ECMAScript 引擎都会隐式的用相同 string 值创建新的 string 对象。此对象只用于此请求,以后每次视图调用 string值方法是都会重新创建。

下面的代码将要求脚本引擎创建21个新 string 对象,每次使用 length 属性时都会产生一个,每一个 charAt 方法也会产生一个:

var s = '0123456789'; for( var i = 0; i < s.length; i++ ) { s.charAt(i); }

下面的代码和上面相同,但只创建了一个对象,因此其效率更高:

复制代码 代码如下:

var s = new String('0123456789'); for( var i = 0; i < s.length; i++ ) { s.charAt(i); }

如果代码中常调用 literal 值的方法,你应像上面例子那样考虑创建对象。

注意本文中大部分技巧对于所有浏览器都有效,但此技巧特别针对于 Opera。此优化技巧在 Internet Explorer 和 Firefox 中改进效果没有在 Opera 中明显。

在关键函数中避免 for-in

for-in 常被误用,特别是简单的 for 循环更合适时。for-in 循环需要脚本引擎创建所有可枚举的属性列表,然后检查是否存在重复。

有时脚本已知可枚举的属性。这时简单的 for 循环即可遍历所有属性,特别是当使用顺序数字枚举时,如数组中。

下面是不正确的 for-in 循环使用:

复制代码 代码如下:

var oSum = 0; for( var i in oArray ) { oSum += oArray[i]; }

for 循环无疑会更高效:

复制代码 代码如下:

var oSum = 0; var oLength = oArray.length; for( var i = 0; i < oLength; i++ ) { oSum += oArray[i]; }

优化 string 合并

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdsjzs.html