文章目录
- 1. 避免全局查找
- 2. 使用setInterval替换setTimeout
- 3. 字符串连接
- 4. 避免with语句
- 5. 数字转换成字符串
- 6. 浮点数转换成整型
- 7. 类型转换
- 8. 多个类型声明
- 9. 插入迭代
- 10. 使用直接量
- 11. 使用DocumentFragment优化多次append
- 12. 使用一次innerHTML赋值代替构建dom元素
- 13. 通过模板元素clone,替代createElement
- 14. 使用firstChild和nextSibling代替childNodes遍历dom元素
- 15. 删除DOM节点
- 16. 使用事件代理
- 17. 重复使用的调用结果,事先保存到局部变量
- 18. 注意html集合
- 19. 循环优化
- 20. 展开循环
- 21. 避免双重求值
- 22. 缩短否定检测
- 23. 条件分支
- 24. 使用常量
- 26. 避免全局函数
- 27. 尊重对象的所有权
- 28. 避免循环引用
- 29. 通过javascript创建的dom对象,必须append到页面中
- 30. 释放dom元素占用的内存
- 31. 释放javascript对象
- 32. 巧用||与&&
- 参考文献
1. 避免全局查找
在一个函数中会用到全局对象存储为局部变量来减少全局查找,因为访问局部变量的速度要比访问全局变量的速度更快些。
2. 使用setInterval替换setTimeout
如果针对的是不断运行的代码,不应该使用setTimeout,而应该是用setInterval,因为setTimeout每一次都会初始化一个定时器,而setInterval只会在开始的时候初始化一个定时器。
3. 字符串连接
如果要连接多个字符串,应该少使用+=,如:
x+=a;
x+=b;
x+=c;
应该写成 x+= a + b + c;
而如果是收集字符串,比如多次对同一个字符串进行+=操作的话,最好使用一个缓存,使用JavaScript数组来收集,最后使用join方法连接起来。
4. 避免with语句
和函数类似 ,with语句会创建自己的作用域,因此会增加其中执行的代码的作用域链的长度,由于额外的作用域链的查找,在with语句中执行的代码肯定比外面执行的代码要慢,在能不使用with语句的时候尽量不要使用with语句。
let a={b:{c:{d:{p1:"xx",p2:'xx'}}}};
with(a.b.c.d){
p1 =1;
p2 =2;
}
console.log(a.b.c.d.p1)
let obj = a.b.c.d;
obj.p1 = 1;
obj.p2 = 2;
console.log(obj.p1);
5. 数字转换成字符串
一般最好用"" + 1来将数字转换成字符串,虽然看起来比较丑一点,但事实上这个效率是最高的,性能上来说:("" +) > String() > .toString() > new String()
6. 浮点数转换成整型
很多人喜欢使用parseInt(),其实parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,我们应该使用Math.floor()或者Math.round()。
7. 类型转换
var myVar = '3',
str = ""+myVar, // to string
i_int = ~~ myVar, // to integer
f_float = 1 * myVar, // to float
f_float1 = + myVar,// to float
b_bool = !!myVar, // to bool
arr = [myVar]; // to arry
console.log(typeof myVar)
console.log(typeof str)
console.log(typeof i_int)
console.log(typeof f_float)
console.log(typeof b_bool)
console.log(arr instanceof Array)
console.log( myVar)
console.log( str)
console.log( i_int)
console.log( f_float)
console.log( b_bool)
console.log( Array)
console.log(+myVar)
console.log(typeof (+myVar))
8. 多个类型声明
在JavaScript中所有变量都可以使用单个var语句来声明,这样就是组合在一起的语句,以减少整个脚本的执行时间,就如上面代码一样,上面代码格式也挺规范,让人一看就明了。
var myVar = '3',
str = ""+myVar, // to string
i_int = ~~ myVar, // to integer
f_float = 1 * myVar, // to float
f_float1 = + myVar,// to float
b_bool = !!myVar, // to bool
arr = [myVar]; // to arry
9. 插入迭代
10. 使用直接量
// 创建对象
var myObject = new Object();
myObject.name = 'xx'
// 使用直接量
var myObject1 = {};
myObject1.name = 'xx'
直接量运行得更快,直接量节省代码
11. 使用DocumentFragment优化多次append
由于dom操作天生就慢。一旦需要更新DOM,请考虑使用文档碎片来构建DOM结构(减少访问dom的次数),然后再将其添加到现存的文档中。
for(let i=1000;i>0;i--){
let el = document.createElement('p');
el.innerHTML = i;
document.body.appendChild(el)
}
/*替换为 */
let frag = document.createDocumentFragment();
for(let i=1000;i>0;i--){
let el = document.createElement('p');
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
12. 使用一次innerHTML赋值代替构建dom元素
对于大的DOM更改,使用innerHTML要比使用标准的DOM方法创建同样的DOM结构快得多。
let frag = document.createDocumentFragment();
for(let i=1000;i>0;i--){
let el = document.createElement('p');
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
/* 可替换为 */
let html=[];
for(let i=1000;i>0;i--){
html.push('<p>'+i+'</p>');
}
document.body.innerHTML = html.join('');
13. 通过模板元素clone,替代createElement
很多人喜欢在JavaScript中使用document.write来给页面生成内容。事实上这样的效率较低,如果需要直接插入HTML,可以找一个容器元素,比如指定一个div或者span,并设置他们的innerHTML来将自己的HTML代码插入到页面中。通常我们可能会使用字符串直接写HTML来创建节点,其实这样做,1无法保证代码的有效性2字符串操作效率低,所以应该是用document.createElement()方法,而如果文档中存在现成的样板节点,应该是用cloneNode()方法,因为使用createElement()方法之后,你需要设置多次元素的属性,使用cloneNode()则可以减少属性的设置次数——同样如果需要创建很多元素,应该先准备一个样板节点。
let frag = document.createDocumentFragment();
for(let i=1000;i;i--){
let el = document.createElement('p');
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
/* 可替换为 */
let frag = document.createDocumentFragment();
let pEl = document.getElementsByTagName('p')[0];
for(let i=1000;i;i--){
let el = pEl.cloneNode(false);
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
14. 使用firstChild和nextSibling代替childNodes遍历dom元素
ie种nextSibling比childNodes快很多。其它浏览器运行时间几乎差不多
let nodes = element.childNodes;
// childNodes 是个元素集合,注意缓存length熟悉,避免查找
for(let i=0,l=nodes.lenght;i<l;++i){
let node = nodes[i]
}
// 可以替换为:(ie种nextSibling逼childNodes快很多。其它浏览器运行时间几乎差不多)
let node = element.firstChild;
while(node){
node = node.nextSibling;
}
15. 删除DOM节点
删除dom节点之前,一定要删除注册在该节点上的事件,不管是用observe方式还是用attachEvent方式注册的事件,否则将会产生无法回收的内存。另外,在removeChild和innerHTML=’’二者之间,尽量选择后者. 因为在sIEve(内存泄露监测工具)中监测的结果是用removeChild无法有效地释放dom节点。
16. 使用事件代理
多一个函数,就会多占用内存。避免了多次访问dom
17. 重复使用的调用结果,事先保存到局部变量
let n1 = element.clientHeight + num1;
let n2 = element.clientHeight + num2;
// 替换为
let eleHeight = element.clientHeight;
let n1 = eleHeight + num1;
let n2 = eleHeight + num2;
18. 注意html集合
- document.getElementsByName()
- document.getElementsByClassName()
- document.getElementsByTagName()
- document.images
- document.links
- document.forms
- document.forms[0].elements
返回的都是一个html集合(类数组对象)
html集合一直与文档保持着连接,你每次需要最新的信息时,都会重复执行查询功能,哪怕师获取集合的长度
let images= document.getElementsByTagName('img');
for(let i = images.length;i;--i){
}
19. 循环优化
- 倒序迭代
let images= document.getElementsByTagName('img');
for(let i = images.length;i;--i){
}
20. 展开循环
当循环次数是确定的,消除循环并使用多次函数调用往往会更快。
21. 避免双重求值
避免使用,eval(),Function() 构造函数(setTimeOut(),setInterval()避免传入字符串,建议传入函数。因为每次调用它们时,都要创建一个新的解释器/编译器实例
22. 缩短否定检测
if(flag != 'abc'){
}
if(flag != null){
}
if(flag != false){
}
// 可以替换为
if(!flag){
}
if(o == '' || o == undefined || o == null){
}
// 可以替换为
if(!!o){
}
23. 条件分支
- 建议使用switch。switch由于if-else。
- 将最可能出现的条件放在最前面。可以减少解释器对条件的探测次数。
- 使用三目运算符替代条件分支。
24. 使用常量
任何在多处用到的值都应该抽取为一个常量
26. 避免全局函数
因为容易造成命名空间污染单例模式
27. 尊重对象的所有权
因为JavaScript可以在任何时候修改任意对象,这样就可以以不可预计的方式覆写默认的行为,所以如果你不负责维护某个对象,它的对象或者它的方法,那么你就不要对它进行修改,具体一点就是说:
- 不要为实例或原型添加属性
- 不要为实例或者原型添加方法
- 不要重定义已经存在的方法
- 不要重复定义其它团队成员已经实现的方法,永远不要修改不是由你所有的对象,你可以通过以下方式为对象创建新的功能。
- 创建包含所需功能的新对象,并用它与相关对象进行交互
- 创建自定义类型,继承需要进行修改的类型,然后可以为自定义类型添加额外功能
28. 避免循环引用
会发生内存泄漏
function init(){
let el = document.getElementById('xx');
el.onclick = function(){
}
}
// init在执行的时候,当前上下文我们叫做context。这个时候,context引用了el,el引用了function,function引用了context。这时候形成了一个循环引用。
function init(){
let el = document.getElementById('xx');
el.onclick = function(){
}
el = null;
}
29. 通过javascript创建的dom对象,必须append到页面中
IE下,脚本创建的dom对象,如果没有append到页面中,刷新页面,这部分内存是不会回收的!
let doms = document.getElementById('app');
for(let i=100;i--;){
let el = document.createElement('p');
el.innerHTML = 'hello'
// 脚本创建的dom对象,如果没有append到页面中,刷新页面,这部分内存是不会回收的!
doms.appendChild(el);
}
30. 释放dom元素占用的内存
将dom元素的innerHTML设置为空字符串,可以释放其子元素占用的内存。在rich应用中,用户也许会在一个页面上停留很长时间,可以使用该方法释放积累得越来越多的dom元素使用的内存。
31. 释放javascript对象
在rich应用中,随着实例化对象数量的增加,内存消耗会越来越大。所以应当及时释放对对象的引用,让GC能够回收这些内存控件。
对象:obj = null
对象属性:delete obj.myproperty
数组item:使用数组的splice方法释放数组中不用的item
32. 巧用||与&&
function eventHandler(e){
if(!e) e = window.event;
}
// 可以替换位
function eventHandler(e){
e = e|| window.event
}
if(myObj){
doSomthing(myObj);
}
// 可以替换为
myObj && doSomthing(myObj);