请把以下用于连接字符串的JavaScript代码修改为更高效的方式:

var htmlString ='< div class=”container” > ' + '< ul id=”news-list” > ';
for (var i = 0; i < NEWS.length; i++) {
htmlString += '< li > < a href="' +NEWS[i].LINK +'" > +NEWS[i].TITLE + '< /a > < /li >';
}
htmlString += '< /ul > < /div > ';

zhiyelee的回答:

 
考点有两个:
  1. JavaScript的字符串连接机制。
  2. NEWS.length需要缓存,不然每次循环都要重新计算一次length

===============
主要看一下第一个:
在js里字符串一旦赋值后不能修改。

基于这个背景看一下字符串连接操作:
var str ;
str = 'this is a string';
str = str + ',another string.';

对于这个连接操作JS的处理机制是:新建一个临时字符串,将新字符串赋值为 str + ',another string.' ,然后返回这个新字符串并同时销毁原始字符串。所以字符串的连接效率较低。提高效率的办法是用数组的join函数:

var tempArr = [] ,src,res;
src = 'this is a string';
tempArr.push(src);
tempArr.push(',another string.');
res = tempArr.join('');
不过在《JavaScript高级程序设计》里也提到:
这个过程是在后台发生的,而这也是在某些旧版本的浏览器(例如版本低于1.0的FireFox、IE6等)中拼接字符串是速度很慢的原因。但这些浏览器后来的版本已经解决了这个问题。
所以效率提高也只是在IE6 等低版本的浏览器中有效。
 
————————————————————————————————————
关于此问题的更多知识,参考了hax的JS优化原则
 
JS优化已经讨论了很多了,最近又看到aimingoo的一篇。大体上,aimingoo的说法都是非常正确的。

除了像aimingoo做个案研究外,这里我想从更一般的角度总结在浏览器编程中JS优化的几个原则。

首先,与其他语言不同,JS的效率很大程度是取决于JS engine的效率。除了引擎实现的优劣外,引擎自己也会为一些特殊的代码模式采取一些优化的策略。例如FF、Opera和Safari的JS引擎,都对字符串的拼接运算(+)做了特别优化。显然,要获得最大效率,就必须要了解引擎的脾气,尽量迎合引擎的口味。所以对于不同的引擎,所作的优化极有可能是背道而驰的。

而如果做跨浏览器的web编程,则最大的问题是在于IE6(JScript 5.6)!因为在不打hotfix的情况下,JScript引擎的垃圾回收的bug,会导致其在真实应用中的performance跟其他浏览器根本不在一个数量级上。因此在这种场合做优化,实际上就是为JScript做优化!

所以第一原则就是只需要为IE6(未打补丁的JScript 5.6或更早版本)做优化

如果你的程序已经优化到在IE6下可以接受的性能,那基本上在其他浏览器上性能就完全没有问题。

因此,注意我下面讲的许多问题在其他引擎上可能完全不同,例如在循环中进行字符串拼接,通常认为需要用Array.join的方式,但是由于SpiderMonkey等引擎对字符串的“+”运算做了优化,结果使用Array.join的效率反而不如直接用“+”!但是如果考虑IE6,则其他浏览器上的这种效率的差别根本不值一提。

JS优化与其他语言的优化也仍然有相同之处。比如说,不要一上来就急吼吼的做优化,那样毫无意义。优化的关键,仍然是要把精力放在最关键的地方,也就是瓶颈上。一般来说,瓶颈总是出现在大规模循环的地方。这倒不是说循环本身有性能问题,而是循环会迅速放大可能存在的性能问题。

所以第二原则就是以大规模循环体为最主要优化对象

以下的优化原则,只在大规模循环中才有意义,在循环体之外做此类优化基本上是没有意义的。

目前绝大多数JS引擎都是解释执行的,而解释执行的情况下,在所有操作中,函数调用的效率是较低的。此外,过深的prototype继承链或者多级引用也会降低效率。JScript中,10级引用的开销大体是一次空函数调用开销的1/2。这两者的开销都远远大于简单操作(如四则运算)。

所以第三原则就是尽量避免过多的引用层级和不必要的多次方法调用

特别要注意的是,有些情况下看似是属性访问,实际上是方法调用。例如所有DOM的属性,实际上都是方法。在遍历一个NodeList的时候,循环条件对于nodes.length的访问,看似属性读取,实际上是等价于函数调用的。而且IE DOM的实现上,childNodes.length每次是要通过内部遍历重新计数的。(My god,但是这是真的!因为我测过,childNodes.length的访问时间与childNodes.length的值成正比!)这非常耗费。所以预先把nodes.length保存到js变量,当然可以提高遍历的性能。

同样是函数调用,用户自定义函数的效率又远远低于语言内建函数,因为后者是对引擎本地方法的包装,而引擎通常是c,c++,java写的。进一步,同样的功能,语言内建构造的开销通常又比内建函数调用要效率高,因为前者在JS代码的parse阶段就可以确定和优化。

所以第四原则就是尽量使用语言本身的构造和内建函数

这里有一个例子是高性能的String.format方法。String.format传统的实现方式是用String.replace(regex, func),在pattern包含n个占位符(包括重复的)时,自定义函数func就被调用n次。而这个高性能实现中,每次format调用所作的只是一次Array.join然后一次String.replace(regex, string)的操作,两者都是引擎内建方法,而不会有任何自定义函数调用。两次内建方法调用和n次的自定义方法调用,这就是性能上的差别。

同样是内建特性,性能上也还是有差别的。例如在JScript中对于arguments的访问性能就很差,几乎赶上一次函数调用了。因此如果一个可变参数的简单函数成为性能瓶颈的时候,可以将其内部做一些改变,不要访问arguments,而是通过对参数的显式判断来处理。

比如:

function sum() {
var r = 0;
for (var i = 0; i < arguments.length; i++) {
r += arguments[i];
}
return r;
}
 

这个sum通常调用的时候个数是较少的,我们希望改进它在参数较少时的性能。如果改成:

其实并不会有多少提高,但是如果改成:

function sum(a, b, c, d, e, f, g) {
var r = a ? b ? c ? d ? e ? f ? a + b + c + d + e + f : a + b + c + d + e : a + b + c + d : a + b + c : a + b : a : 0;
if (g === undefined) return r;
for (var i = 6; i < arguments.length; i++) {
r += arguments[i];
}
return r;
}
就会提高很多(至少快1倍)。

最后是第五原则,也往往是真实应用中最重要的性能障碍,那就是尽量减少不必要的对象创建

本身创建对象是有一定的代价的,但是这个代价其实并不大。最根本的问题是由于JScript愚蠢之极的垃圾回收调度算法,导致随着对象个数的增加,性能严重下降(据微软的人自己说复杂度是O(n^2))。

比如我们常见的字符串拼接问题,经过我的测试验证,单纯的多次创建字符串对象其实根本不是性能差的原因。要命的是在对象创建期间的无谓的垃圾回收的开销。而Array.join的方式,不会创建中间字符串对象,因此就减少了那该死的垃圾回收的开销。

因此,如果我们能把大规模对象创建转化为单一语句,则其性能会得到极大的提高!例如通过构造代码然后eval——实际上PIES项目中正在根据这个想法来做一个专门的大规模对象产生器……

好了上面就是偶总结的JS优化五大原则。

除了这些原则以外,还有一些特殊情况,如DOM的遍历,以后有时间再做讨论。

 

从字符串拼接看JS优化原则的更多相关文章

  1. js优化原则

    首先,与其他语言不同,JS的效率很大程度是取决于JS engine的效率.除了引擎实现的优劣外,引擎自己也会为一些特殊的代码模式采取一些优化的策略.例如FF.Opera和Safari的JS引擎,都对字 ...

  2. JS模板引擎:基于字符串拼接

    目的 编写一个基于字符串拼接的js模板引擎雏形,这里并不会提供任何模板与数据的绑定. 基本原理 Javascript中创建函数的方式有多种,包括: 1. var func = function () ...

  3. JS字符串拼接优化

    // 请把以下用于连接字符串的JavaScript代码修改为更高效的方式 var htmlString = ‘ < div class=”container” > ’ + ‘ < u ...

  4. 【javaScript】js出现allocation size overflow以及字符串拼接优化

    字符串拼接长一点了,就出现了allocation size overflow异常! 先创建缓冲字符串数组,最后将数组转化为字符串 <script type="text/javascri ...

  5. JS数据模板分离(告别字符串拼接)-template

    刚开始在写第一个动态网页的demo时,由于html不多,便使用字符串拼接的方法添加到dom来渲染,可是在后来写某外卖app时也需要如此添加,打开代码一看几千行,突然感觉累觉不爱 一行行的拼接有这功夫别 ...

  6. html转js字符串拼接

    https://www.bejson.com/convert/html_js/ html转js字符串拼接

  7. js扩展String.prototype.format字符串拼接的功能

    1.题外话,有关概念理解:String.prototype 属性表示 String原型对象.所有 String 的实例都继承自 String.prototype. 任何String.prototype ...

  8. Js 字符串拼接的两种方法

    字符串拼接的两种方法 用数组的方法的好处是:避免变量重新定义.赋值 <!DOCTYPE html> <html lang="en"> <head> ...

  9. js 字符串拼接、截取、查找...

    函数:split() 功能:使用一个指定的分隔符把一个字符串分割存储到数组 例子: let str=”020-88888888-03”; let arr=str.split(”-”); console ...

随机推荐

  1. 解决IOS safari在input focus弹出输入法时不支持position fixed的问题

    该文章为转载 我们在做移动web应用的时候,常常习惯于使用position:fixed把一个input框作为提问或者搜索框固定在页面底部.但在IOS的safari和webview中,对position ...

  2. Android Studio的使用(九)--设置IDE编码格式

    1.打开设置 2.勾选编码格式,在这里可以设置分别设置IDE.Project.File等级别的编码格式. 3.查看.修改各个文件的编码 4.当右击编辑界面时,可以直接设置当前文件的编码

  3. JSP标准标签库(JSTL)--核心标签库 c

    核心标签库是JSTL中最重要的部分,可以完成输出,判断,迭代等操作 功能分类: 1. 基本标签: <c:out>:输出属性内容 <c:set>:设置属性内容 <c:rem ...

  4. zf-启动项目报错Server 127.0.0.1 has no instance named dlx 解决办法

    由于百度出来的看不明白,于是我就在群里问,吴善如经理说:你这个问题我上次给李宽看过,用端口连,把instance去掉 然后我去掉之后 项目过程能够成功运行了,原来是这样

  5. jquery has deprecated synchronous XMLHTTPRequest

    Like many others, my website is using jquery. When I open the developer tools, I see a warning that ...

  6. [转]HTTPS连接的前几毫秒发生了什么

    本文由 伯乐在线 - 水果泡腾片 翻译.未经许可,禁止转载!英文出处:JEFF MOSER.欢迎加入翻译小组. 提示:英文原文写于2009年,当时的Firefox和最新版的Firefox,界面也有很大 ...

  7. 转:web_submit_data和web_submit_form的差别

    在LoadRunner中有两个常用函数:Web_submit_form和Web_submit_data,在群里有人问这两个函数有什么区别.为什么会有两个不同却功能相似的函数.区别在哪里. 首先,从工具 ...

  8. Base64编码与图片互转

    import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import ...

  9. 关于nodejs的require顺序

    --------------------------------------- check /home/somebody/node_modules/othermodule check /home/so ...

  10. tomcat webdav

    <servlet> <servlet-name>webdav</servlet-name> <servlet-class>org.apache.cata ...