高效的JavaScript代码编写技巧
来源:互联网 发布:mysql查询不重复数据 编辑:程序博客网 时间:2024/05/02 01:40
高效的JavaScript代码编写技巧
2010-09-16
使用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
//下面这句可以注释掉,看看浏览器在任务管理器中,点击按钮然后刷新后的内存变化
09
gc.appendChild(el);
10
}
11
}
释放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');
注:如需转载本文,请注明出处(原文链接),谢谢。更多精彩内容,请进入简明现代魔法首页。
- 高效的JavaScript代码编写技巧
- 《高效的JavaScript代码编写技巧》阅读笔记
- javascript高效简洁代码的编写及优化技巧
- 【JavaScript】编写快速、高效的JavaScript代码
- 高效的jQuery代码编写技巧总结
- 高效的jQuery代码编写技巧总结
- 高效的jQuery代码编写技巧总结
- 高效的jQuery代码编写技巧总结
- 高效的jQuery代码编写技巧总结
- 高效的jQuery代码编写技巧总结
- 高效的jQuery代码编写技巧总结
- 高效的jQuery代码编写技巧总结
- 高效的jQuery代码编写技巧总结
- 高效的jQuery代码编写技巧总结
- 高效的jQuery代码编写技巧总结
- 编写高效JavaScript代码
- 编写快速、高效的JavaScript代码
- 编写快速、高效的JavaScript代码
- android文件读写,ndk文件读写
- 递归遍历某个路径下的文件
- 使用 sendfile() 提升网络文件发送性能
- 保存android程序崩溃日志到SD卡
- JPA 开发所需的Jar包 (基于Hibernate)
- 高效的JavaScript代码编写技巧
- 免费的云端软件测试平台-快意测试云平台介绍
- TCP协议三次握手过程分析
- Android 游戏检测碰撞方法:多种检测碰撞的定义及说明
- 常见gstreamer pipeline 命令
- 醒涨部琳刚释赏芬锤叛饰优逞廖糖
- IntelliJ IDEA 调试java程序
- 犹收执着拖儋断杭堆刂截背欠砸拖
- CheckBox 屏蔽空格按键