高效率JavaScript代码的编写技巧

使用DocumentFragment优化多次append

添加多个dom元素时,先将元素append到DocumentFragment中,最后统一将DocumentFragment添加到页面。该做法可以减少页面渲染dom元素的次数。经IE和FX下测试,在append1000个元素时,效率能提高10%-30%,FX下提升较为明显。兴城市费永礼品

前:

1 for (var i = 0; i < 1000; i++) {
2     var el = document.createElement(‘p‘);
3     el.innerHTML = i;
4     document.body.appendChild(el);
5 }

后:

1 var frag = document.createDocumentFragment();
2 for (var i = 0; i < 1000; i++) {
3     var el = document.createElement(‘p‘);
4     el.innerHTML = i;
5     frag.appendChild(el);
6 }
7 document.body.appendChild(frag);

通过模板元素clone,替代createElement

通过一个模板dom对象cloneNode,效率比直接创建element高。性能提高不明显,约为10%左右。在低于100个元素create和append操作时,没有优势。

1 var frag = document.createDocumentFragment();
2 for (var i = 0; i < 1000; i++) {
3     var el = document.createElement(‘p‘);
4     el.innerHTML = i;
5     frag.appendChild(el);
6 }
7 document.body.appendChild(frag);   
1 var frag = document.createDocumentFragment();
2 var pEl = document.getElementsByTagName(‘p‘)[0];
3 for (var i = 0; i < 1000; i++) {
4     var el = pEl.cloneNode(false);
5     el.innerHTML = i;
6     frag.appendChild(el);
7 }
8 document.body.appendChild(frag);

使用一次innerHTML赋值代替构建dom元素

根据数据构建列表样式的时候,使用设置列表容器innerHTML的方式,比构建dom元素并append到页面中的方式,效率有数量级上的提高。

1 var frag = document.createDocumentFragment();
2 for (var i = 0; i < 1000; i++) {
3     var el = document.createElement(‘p‘);
4     el.innerHTML = i;
5     frag.appendChild(el);
6 }
7 document.body.appendChild(frag);
1 var html = [];
2 for (var i = 0; i < 1000; i++) {
3     html.push(‘<p>‘ + i + ‘</p>‘);
4 }
5 document.body.innerHTML = html.join(‘‘);

使用firstChild和nextSibling代替childNodes遍历dom元素

约能获得30%-50%的性能提高。逆向遍历时使用lastChild和previousSibling。

1 var nodes = element.childNodes;
2 for (var i = 0, l = nodes.length; i < l; i++) {
3 var node = nodes[i];
4 ……
5 }
1 var node = element.firstChild;
2 while (node) {
3 ……
4 node = node.nextSibling;
5 }

使用Array做为StringBuffer,代替字符串拼接的操作

IE在对字符串拼接的时候,会创建临时的String对象;经测试,在IE下,当拼接的字符串越来越大时,运行效率会急剧下降。Fx和Opera都对字符串拼接操作进行了优化;经测试,在Fx下,使用Array的join方式执行时间约为直接字符串拼接的1.4倍。

1 var now = new Date();
2 var str = ‘‘;
3 for (var i = 0; i < 10000; i++) {
4     str += ‘123456789123456789‘;
5 }
6 alert(new Date() - now);
1 var now = new Date();
2 var strBuffer = [];
3 for (var i = 0; i < 10000; i++) {
4     strBuffer.push(‘123456789123456789‘);
5 }
6 var str = strBuffer.join(‘‘);
7 alert(new Date() - now);

将循环控制量保存到局部变量

对数组和列表对象的遍历时,提前将length保存到局部变量中,避免在循环的每一步重复取值。

1 var list = document.getElementsByTagName(‘p‘);
2 for (var i = 0; i < list.length; i++) {
3     ……
4 }
1 var list = document.getElementsByTagName(‘p‘);
2 for (var i = 0, l = list.length; i < l; i++) {
3     ……
4 }

顺序无关的遍历时,用while替代for

该方法可以减少局部变量的使用。比起效率优化,更能直接看到的是字符数量的优化。该做法有程序员强迫症的嫌疑。

1 var arr = [1,2,3,4,5,6,7];
2 var sum = 0;
3 for (var i = 0, l = arr.length; i < l; i++) {
4     sum += arr[i];
5 }   
1 var arr = [1,2,3,4,5,6,7];
2 var sum = 0, l = arr.length;
3 while (l--) {
4     sum += arr[l];
5 }

使用三目运算符替代条件分支

1 if (a > b) {
2 num = a;
3 else {
4 num = b;
5 }
1 num = a > b ? a : b;

需要不断执行的时候,优先考虑使用setInterval

setTimeout每一次都会初始化一个定时器。setInterval只会在开始的时候初始化一个定时器。

1 var timeoutTimes = 0;
2 function timeout () {
3     timeoutTimes++;
4     if (timeoutTimes < 10) {
5         setTimeout(timeout, 10);
6     }
7 }
8 timeout();
1 var intervalTimes = 0;
2 function interval () {
3     intervalTimes++;
4     if (intervalTimes >= 10) {
5         clearInterval(interv);
6     }
7 }
8 var interv = setInterval(interval, 10);

使用function而不是string

如果把字符串作为setTimeout和setInterval的参数,浏览器会先用这个字符串构建一个function。

1 var num = 0;
2 setTimeout(‘num++‘, 10);
1 var num = 0;
2 function addNum () {
3     num++;
4 }
5 setTimeout(addNum, 10);

重复使用的调用结果,事先保存到局部变量

避免多次取值的调用开销。

1 var h1 = element1.clientHeight + num1;
2 var h2 = element1.clientHeight + num2;
1 var eleHeight = element1.clientHeight;
2 var h1 = eleHeight + num1;
3 var h2 = eleHeight + num2;

使用直接量

1 var a = new Array(param,param,...) -> var a = []
2 var foo = new Object() -> var foo = {}
3 var reg = new RegExp() -> var reg = /.../

避免使用with

with虽然可以缩短代码量,但是会在运行时构造一个新的scope。OperaDev上还有这样的解释,使用with语句会使得解释器无法在语法解析阶段对代码进行优化。对此说法,无法验证。

1 with (a.b.c.d) {
2 property1 = 1;
3 property2 = 2;
4 }
1 var obj = a.b.c.d;
2 obj.property1 = 1;
3 obj.property2 = 2;

巧用||和&&布尔运算符

1 function eventHandler (e) {
2 if(!e) e = window.event;
3 }
1 function eventHandler (e) {
2 e = e || window.event;
3 }

还有下面的例子:

1 if (myobj) {
2 doSomething(myobj);
3 }
1 myobj && doSomething(myobj);

类型转换

数字转换成字符串,应用"" + 1,性能上:("" +) > String() > .toString() > new String();

浮点数转换成整型,不使用parseInt(), parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,建议使用Math.floor()或者Math.round()。

对于自定义的对象,推荐显式调用toString()。内部操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String。

循环引用

如果循环引用中包含DOM对象或者ActiveX对象,那么就会发生内存泄露。内存泄露的后果是在浏览器关闭前,即使是刷新页面,这部分内存不会被浏览器释放。

简单的循环引用:

1 var el = document.getElementById(‘MyElement‘);
2 var func = function () {…}
3 el.func = func;
4 func.element = el;

但是通常不会出现这种情况。通常循环引用发生在为dom元素添加闭包作为expendo的时候。

1 function init() {
2     var el = document.getElementById(‘MyElement‘);
3 el.onclick = function () {……}
4 }
5 init();

init在执行的时候,当前上下文我们叫做context。这个时候,context引用了el,el引用了function,function引用了context。这时候形成了一个循环引用。

置空dom对象

1 function init() {
2 var el = document.getElementById(‘MyElement‘);
3 el.onclick = function () {……}
4 }
5 init();
1 function init() {
2 var el = document.getElementById(‘MyElement‘);
3 el.onclick = function () {……}
4 el = null;
5 }
6 init();

将el置空,context中不包含对dom对象的引用,从而打断循环应用。如果我们需要将dom对象返回,可以用如下方法:

1 function init() {
2     var el = document.getElementById(‘MyElement‘);
3     el.onclick = function () {……}
4     return el;
5 }
6 init();
01 function init() {
02 var el = document.getElementById(‘MyElement‘);
03 el.onclick = function () {……}
04 try{
05 return el;
06 } finally {
07     el = null;
08 }
09 }
10 init();

构造新的context:

1 function init() {
2     var el = document.getElementById(‘MyElement‘);
3     el.onclick = function () {……}
4 }
5 init();
1 function elClickHandler() {……}
2 function init() {
3     var el = document.getElementById(‘MyElement‘);
4     el.onclick = elClickHandler;
5 }
6 init();

把function抽到新的context中,这样,function的context就不包含对el的引用,从而打断循环引用。

通过javascript创建的dom对象,必须append到页面中

IE下,脚本创建的dom对象,如果没有append到页面中,刷新页面,这部分内存是不会回收的!

01 function create () {
02     var gc = document.getElementById(‘GC‘);
03     for (var i = 0; i < 5000 ; i++)
04     {
05         var el = document.createElement(‘div‘);
06         el.innerHTML = "test";
07         //下面这句可以注释掉,看看浏览器在任务管理器中,点击按钮然后刷新后的内存变化
08         gc.appendChild(el);
09     }
10 }

释放dom元素占用的内存

将dom元素的innerHTML设置为空字符串,可以释放其子元素占用的内存。

在rich应用中,用户也许会在一个页面上停留很长时间,可以使用该方法释放积累得越来越多的dom元素使用的内存。

释放javascript对象

在rich应用中,随着实例化对象数量的增加,内存消耗会越来越大。所以应当及时释放对对象的引用,让GC能够回收这些内存控件。

对象:obj = null,对象属性:delete obj.myproperty。

数组item:使用数组的splice方法释放数组中不用的item。

避免string的隐式装箱

对string的方法调用,比如‘xxx‘.length,浏览器会进行一个隐式的装箱操作,将字符串先转换成一个String对象。推荐对声明有可能使用String实例方法的字符串时,采用如下写法:

var myString = new String(‘Hello World‘);

时间: 2024-08-11 03:36:21

高效率JavaScript代码的编写技巧的相关文章

你可能不知道的JavaScript代码片段和技巧(上)

JavaScript是一个绝冠全球的编程语言,可用于Web开发.移动应用开发(PhoneGap.Appcelerator).服务器端开发(Node.js和Wakanda等等.JavaScript还是很多新手踏入编程世界的第一个语言.既可以用来显示浏览器中的简单提示框,也可以通过nodebot或nodruino来控制机器人.能够编写结构清晰.性能高效的JavaScript代码的开发人员,现如今已成了招聘市场最受追捧的人. 在这篇文章里,我将分享一些JavaScript的技巧.秘诀和最佳实践,除了少

你可能不知道的JavaScript代码片段和技巧(下)

JavaScript是一个绝冠全球的编程语言,可用于Web开发.移动应用开发(PhoneGap.Appcelerator).服务器端开发(Node.js和Wakanda等等.JavaScript还是很多新手踏入编程世界的第一个语言.既可以用来显示浏览器中的简单提示框,也可以通过nodebot或nodruino来控制机器人.能够编写结构清晰.性能高效的JavaScript代码的开发人员,现如今已成了招聘市场最受追捧的人. 在这篇文章里,我将分享一些JavaScript的技巧.秘诀和最佳实践,除了少

Emmet:HTML/CSS代码快速编写技巧

一.Emmet简介 Emmet的前身是Zen Coding,它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,由两个核心组件组成:一个缩写扩展器(缩写为像CSS一样的选择器)和上下文无关的HTML标签对匹配器. 二.快速编写HTML代码 1.初始化 HTML文档需要包含一些固定的标签,比如<html>,<head>,<body>等,利用Emmet可以1秒钟就可以完成这些标签的输入. 比如:输入“!”或“html:5”,然后按Tab键,就能生

新书《编写可测试的JavaScript代码 》出版,感谢支持

本书介绍 JavaScript专业开发人员必须具备的一个技能是能够编写可测试的代码.不管是创建新应用程序,还是重写遗留代码,本书都将向你展示如何为客户端和服务器编写和维护可测试的JavaScript代码. 从减少代码复杂性的方法,到单元测试.代码覆盖率.调试.以及自动化,您将全面学到如何编写让你和你同事能够轻松修复和维护的JavaScript代码.测试JavaScript代码是一个复杂的过程.本书将在很大程度上帮你简化该过程. 目标读者 本书主要目标受众是那些想成为JavaScript专业开发人

使用 Promises 编写更优雅的 JavaScript 代码

你可能已经无意中听说过 Promises,很多人都在讨论它,使用它,但你不知道为什么它们如此特别.难道你不能使用回调么?有什么了特别的?在本文中,我们一起来看看 Promises 是什么以及如何使用它们写出更优雅的 JavaScript 代码. 您可能感兴趣的相关文章 开发中可能会用到的几个 jQuery 提示和技巧 精心挑选的优秀jQuery Ajax分页插件和教程 推荐几款很好用的 JavaScript 文件上传插件 精心挑选的优秀 jQuery 文本特效插件和教程 精心挑选12款优秀 jQ

14条最佳JS代码编写技巧

http://gaohaixian.blog.163.com/blog/static/123260105201142645458315/写任何编程代码,不同的开发者都会有不同的见解.但参考一下总是好的,下面是来自Javascript Toolbox发布的14条最佳JS代码编写技巧,Sofish翻译(1,2). 1. 总是使用 ‘var’ 在javascript中,变量不是全局范围的就是函数范围的,使用”var”关键词将是保持变量简洁明了的关键.当声明一个或者是全局或者是函数级(function-

编写高质量JavaScript代码的68个有效方法

简介: <Effective JavaScript:编写高质量JavaScript代码的68个有效方法>共分为7章,分别涵盖JavaScript的不同主题.第1章主要讲述最基本的主题,如版本.类型转换要点.运算符注意事项和分号局限等.第2章主要讲解变量作用域,介绍此方面的一些基本概念,以及一些最佳实践经验.第3章主要讲解函数的使用,深刻解析函数.方法和类,并教会读者在不同的环境下高效使用函数.第4章主要讲解原型和对象,分析JavaScript的继承机制以及原型和对象使用的最佳实践和原则.第5章

编写简洁的 JavaScript 代码

作者:尹锋链接:https://www.zhihu.com/question/20635785/answer/223515216来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 避免使用 js 糟粕和鸡肋 这些年来,随着 HTML5 和 Node.js 的发展,JavaScript 在各个领域遍地开花,已经从"世界上最被误解的语言"变成了"世界上最流行的语言".但是由于历史原因,JavaScript 语言设计中还是有一些糟粕和鸡肋,比如

代码示例:一些简单技巧优化JavaScript编译器工作详解,让你写出高性能运行的更快JavaScript代码

告诉你一些简单的技巧来优化JavaScript编译器工作,从而让你的JavaScript代码运行的更快.尤其是在你游戏中发现帧率下降或是当垃圾回收器有大量的工作要完成的时候. 单一同态: 当你定义了一个两个参数的函数,编译器会接受你的定义,如果函数参数的类型.个数或者返回值的类型改变编译器的工作会变得艰难.通常情况下,单一同态的数据结构和个数相同的参数会让你的程序会更好的工作. function example(a, b) { // 期望a,b都为数值类型 console.log(++a * +