JS代码的执行效率每每直接影响了页面的性能,有的时候,实现一样的功能,不一样的JS代码每每在效率上相差不少,有的时候仅仅是因为咱们的书写习惯致使的,固然在高级点的浏览器中,它们大多都已经帮咱们优化了,但...javascript
JS代码的执行效率每每直接影响了页面的性能,有的时候,实现一样的功能,不一样的JS代码每每在效率上相差不少,有的时候仅仅是因为咱们的书写习惯致使的,固然在高级点的浏览器中,它们大多都已经帮咱们优化了,可是在中国,万恶的IE6仍然大量的存在,咱们不得不去考虑它。对于JS代码的优化,实际上有不少的状况,有些影响是比较小的,而有些是比较严重的,本文中,我把几个我认为影响比较严重的状况列出来,供你们参考。 html
字符串的拼接在咱们开发中会常常遇到,因此我把其放在首位,咱们每每习惯的直接用+=的方式来拼接字符串,其实这种拼接的方式效率很是的低,咱们能够用一种巧妙的方法来实现字符串的拼接,那就是利用数组的join方法。前端
1 <div class="one" id="one"></div> 2 <input type="button" value="效率低" onclick="func1()" /> 3 <input type="button" value="效率高" onclick="func2()" /> 4 5 <script> 6 //效率低的 7 function func1(){ 8 var start = new Date().getTime(); 9 var template = ""; 10 for(var i = 0; i < 10000; i++){ 11 template += "<input type='button' value='a'>"; 12 } 13 var end = new Date().getTime(); 14 document.getElementById("one").innerHTML = template; 15 alert("用时:" + (end - start) + "毫秒"); 16 } 17 18 //效率高的 19 function func2(){ 20 var start = new Date().getTime(); 21 var array = []; 22 for(var i = 0; i < 10000; i++){ 23 array[i] = "<input type='button' value='a'>"; 24 } 25 var end = new Date().getTime(); 26 document.getElementById("one").innerHTML = array.join(""); 27 alert("用时:" + (end - start) + "毫秒"); 28 } 29 </script>
咱们看看其在不一样浏览器下执行的状况java
咱们会发现,在IE6下其差异是至关明显的,其实这种状况在IE的高版本中体现的也很是明显,可是在Firefox下却没有多大的区别,相反第二种的相对效率还要低点,不过只是差异2ms左右,而Chrome也和Firefox相似。另外在这里顺便说明一下,在咱们给数组添加元素的时候,不少人喜欢用数组的原生的方法push,其实直接用arr[i]或者arr[arr.length]的方式要快一点,大概在10000次循环的状况IE浏览器下会有十几毫秒的差异。node
for循环是咱们常常会遇到的状况,咱们先看看下面例子: 程序员
1 <input type="button" value="效率低" onclick="func1()" /> 2 <input type="button" value="效率高" onclick="func2()" /> 3 <script> 4 var arr = []; 5 for(var i = 0; i < 10000; i++){ 6 arr[i] = "<div>" + i + "</div>"; 7 } 8 document.body.innerHTML += arr.join(""); 9 10 //效率低的 11 function func1(){ 12 var divs = document.getElementsByTagName("div"); 13 var start = new Date().getTime(); 14 for(var i = 0; i < divs.length; i++){ 15 //"效率低" 16 } 17 var end = new Date().getTime(); 18 alert("用时:" + (end - start) + "毫秒"); 19 } 20 21 //效率高的 22 function func2(){ 23 var divs = document.getElementsByTagName("div"); 24 var start = new Date().getTime(); 25 for(var i = 0, len = divs.length; i < len; i++){ 26 //"效率高" 27 } 28 var end = new Date().getTime(); 29 alert("用时:" + (end - start) + "毫秒"); 30 } 31 </script>
由上表能够看出,在IE6.0下,其差异是很是明显,而在Firefox和Chrome下几乎没有差异,之因此在IE6.0下会有这种状况,主要是由于for循环在执行中,第一种状况会每次都计算一下长度,而第二种状况倒是在开始的时候计算长度,并把其保存到一个变量中,因此其执行效率要高点,因此在咱们使用for循环的时候,特别是须要计算长度的状况,咱们应该开始将其保存到一个变量中。可是并非只要是取长度都会出现如此明显的差异,若是咱们仅仅是操做一个数组,取得的是一个数组的长度,那么其实两种方式的写法都差很少,咱们看下面的例子:数组
1 <input type="button" value="效率低" onclick="func1()" /> 2 <input type="button" value="效率高" onclick="func2()" /> 3 <script> 4 var arr2 = []; 5 for(var i = 0; i < 10000; i++){ 6 arr2[i] = "<div>" + i + "</div>"; 7 } 8 9 //效率低的 10 function func1(){ 11 var start = new Date().getTime(); 12 for(var i = 0; i < arr2.length; i++){ 13 //"效率低" 14 } 15 var end = new Date().getTime(); 16 alert("用时:" + (end - start) + "毫秒"); 17 } 18 19 //效率高的 20 function func2(){ 21 var start = new Date().getTime(); 22 for(var i = 0, len = arr2.length; i < len; i++){ 23 //"效率高" 24 } 25 var end = new Date().getTime(); 26 alert("用时:" + (end - start) + "毫秒"); 27 } 28 </script>
从上表能够看出,若是仅仅是一个数组的话,咱们看到其实两种写法都是差很少的,其实若是咱们把循环再上调到100000次的话,也仅仅是差异几毫秒而已,因此在数组的状况下,我认为都是同样的。对于for循环的优化,也有人提出不少点,有人认为用-=1,或者从大到小的方式循环等等,我认为是彻底没有必要的,这些优化每每实际状况下根本没有表现出来,换句话说只是计算机级别的微小的变化,可是给咱们带来的倒是代码的可读性大大的下降,因此实在是得不偿失。浏览器
减小页面重绘虽然本质不是JS自己的优化,可是其每每是由JS引发的,而重绘的状况每每是严重影响页面性能的,因此彻底有必要拿出来,咱们看下面例子闭包
1 <div id="demo"></div> 2 <input type="button" value="效率低" onclick="func1()" /> 3 <input type="button" value="效率高" onclick="func2()" /> 4 5 <script> 6 var str = "<div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div><div>这是一个测试字符串</div>"; 7 8 //效率低的 9 function func1(){ 10 var obj = document.getElementById("demo"); 11 var start = new Date().getTime(); 12 for(var i = 0; i < 100; i++){ 13 obj.innerHTML += str + i; 14 } 15 var end = new Date().getTime(); 16 alert("用时 " + (end - start) + " 毫秒"); 17 } 18 19 //效率高的 20 function func2(){ 21 var obj = document.getElementById("demo"); 22 var start = new Date().getTime(); 23 var arr = []; 24 for(var i = 0; i < 100; i++){ 25 arr[i] = str + i; 26 } 27 obj.innerHTML = arr.join(""); 28 var end = new Date().getTime(); 29 alert("用时 " + (end - start) + " 毫秒"); 30 } 31 </script>
在例子中,我只是用了100次的循环,由于若是用10000次循环的话,浏览器基本上就卡住不动了,可是即便是100次的循环,咱们看看下面的执行结果。app
能够看到的是,这简直是一个惊人的结果,仅仅100次的循环,无论是在什么浏览器下,都出现了如此之大的差异,另外咱们还发现,在这里,IE6的执行效率竟然比起Firefox还要好不少,可见Firefox在页面重绘这方面并无作一些的优化。这里还要注意的是,通常影响页面重绘的不只仅是innerHTML,若是改变元素的样式,位置等状况都会触发页面重绘,因此在平时必定要注意这点。
咱们知道,js代码在执行的时候,若是须要访问一个变量或者一个函数的时候,它须要遍历当前执行环境的做用域链,而遍历是从这个做用域链的前端一级一级的向后遍历,直到全局执行环境,因此这里每每会出现一个状况,那就是若是咱们须要常常访问全局环境的变量对象的时候,咱们每次都必须在当前做用域链上一级一级的遍历,这显然是比较耗时的,咱们看下面的例子:
1 <div id="demo"></div> 2 <input id="but1" type="button" onclick="func1()" value="效率低"/> 3 <input id="but2" type="button" onclick="func2()" value="效率高"/> 4 5 <script> 6 function func1(){ 7 var start = new Date().getTime(); 8 for(var i = 0; i < 10000; i++){ 9 var but1 = document.getElementById("but1"); 10 var but2 = document.getElementById("but2"); 11 var inputs = document.getElementsByTagName("input"); 12 var divs = document.getElementsByTagName("div"); 13 var but1 = document.getElementById("but1"); 14 var but2 = document.getElementById("but2"); 15 var inputs = document.getElementsByTagName("input"); 16 var divs = document.getElementsByTagName("div"); 17 var but1 = document.getElementById("but1"); 18 var but2 = document.getElementById("but2"); 19 var inputs = document.getElementsByTagName("input"); 20 var divs = document.getElementsByTagName("div"); 21 var but1 = document.getElementById("but1"); 22 var but2 = document.getElementById("but2"); 23 var inputs = document.getElementsByTagName("input"); 24 var divs = document.getElementsByTagName("div"); 25 var but1 = document.getElementById("but1"); 26 var but2 = document.getElementById("but2"); 27 var inputs = document.getElementsByTagName("input"); 28 var divs = document.getElementsByTagName("div"); 29 var but1 = document.getElementById("but1"); 30 var but2 = document.getElementById("but2"); 31 var inputs = document.getElementsByTagName("input"); 32 var divs = document.getElementsByTagName("div"); 33 } 34 var end = new Date().getTime(); 35 alert("用时 " + (end - start) + " 毫秒"); 36 } 37 38 function func2(){ 39 var start = new Date().getTime(); 40 var doc = document; 41 for(var i = 0; i < 10000; i++){ 42 var but1 = doc.getElementById("but1"); 43 var but2 = doc.getElementById("but2"); 44 var inputs = doc.getElementsByTagName("input"); 45 var divs = doc.getElementsByTagName("div"); 46 var but1 = doc.getElementById("but1"); 47 var but2 = doc.getElementById("but2"); 48 var inputs = doc.getElementsByTagName("input"); 49 var divs = doc.getElementsByTagName("div"); 50 var but1 = doc.getElementById("but1"); 51 var but2 = doc.getElementById("but2"); 52 var inputs = doc.getElementsByTagName("input"); 53 var divs = doc.getElementsByTagName("div"); 54 var but1 = doc.getElementById("but1"); 55 var but2 = doc.getElementById("but2"); 56 var inputs = doc.getElementsByTagName("input"); 57 var divs = doc.getElementsByTagName("div"); 58 var but1 = doc.getElementById("but1"); 59 var but2 = doc.getElementById("but2"); 60 var inputs = doc.getElementsByTagName("input"); 61 var divs = doc.getElementsByTagName("div"); 62 var but1 = doc.getElementById("but1"); 63 var but2 = doc.getElementById("but2"); 64 var inputs = doc.getElementsByTagName("input"); 65 var divs = doc.getElementsByTagName("div"); 66 } 67 var end = new Date().getTime(); 68 alert("用时 " + (end - start) + " 毫秒"); 69 } 70 </script>
上面代码中,第二种状况是先把全局对象的变量放到函数里面先保存下来,而后直接访问这个变量,而第一种状况是每次都遍历做用域链,直到全局环境,咱们看到第二种状况实际上只遍历了一次,而第一种状况倒是每次都遍历了,因此咱们看看其执行结果:
从上表中能够看出,其在IE6下差异仍是很是明显的,并且这种差异在多级做用域链和多个全局变量的状况下还会表现的很是明显。
双重解释的状况也是咱们常常会碰到的,有的时候咱们没怎么考虑到这种状况会影响到效率,双重解释通常在咱们使用eval、new Function和setTimeout等状况下会遇到,咱们看看下面的例子:
1 <div id="demo"></div> 2 <input id="but1" type="button" onclick="func1()" value="效率低"> 3 <input id="but2" type="button" onclick="func2()" value="效率高"> 4 5 <script> 6 var sum, num1 = 1, num2 = 2; 7 function func1(){ 8 var start = new Date().getTime(); 9 for(var i = 0; i < 10000; i++){ 10 var func = new Function("sum+=num1;num1+=num2;num2++;"); 11 func(); 12 } 13 var end = new Date().getTime(); 14 alert("用时 " + (end - start) + " 毫秒"); 15 } 16 17 function func2(){ 18 var start = new Date().getTime(); 19 for(var i = 0; i < 10000; i++){ 20 sum+=num1; 21 num1+=num2; 22 num2++; 23 } 24 var end = new Date().getTime(); 25 alert("用时 " + (end - start) + " 毫秒"); 26 } 27 </script>
第一种状况咱们是使用了new Function来进行双重解释,而第二种是避免了双重解释,咱们看看在不一样浏览器下的表现:
能够看到,在全部的浏览器中,双重解释都是有很大开销的,因此在实际当中要尽可能避免双重解释。
感谢"SeaSunK"对第四点测试报告错误的指正,如今已经修改过来了。至于最后一点提出的func1每次都初始化,没有可比性,因此我给换了eval,结果发现,在IE6.0下仍是有影响,并且在Firefox下,使用eval对效率的影响程度更加厉害,在Firefox下,若是10000次循环,须要十多秒的时间,因此我把循环都变成了1000次。看代码和报告
1 <div id="demo"></div> 2 <input id="but1" type="button" onclick="func1()" value="效率低"> 3 <input id="but2" type="button" onclick="func2()" value="效率高"> 4 <script> 5 var sum, num1 = 1, num2 = 2; 6 function func1(){ 7 var start = new Date().getTime(); 8 for(var i = 0; i < 1000; i++){ 9 eval("sum+=num1;num1+=num2;num2++;"); 10 } 11 var end = new Date().getTime(); 12 alert("用时 " + (end - start) + " 毫秒"); 13 } 14 function func2(){ 15 var start = new Date().getTime(); 16 for(var i = 0; i < 1000; i++){ 17 sum+=num1; 18 num1+=num2; 19 num2++; 20 } 21 var end = new Date().getTime(); 22 alert("用时 " + (end - start) + " 毫秒"); 23 } 24 </script>
1.1 使用DocumentFragment优化屡次append,使用文档碎片
说明:添加多个dom元素时,先将元素append到DocumentFragment中,最后统一将DocumentFragment添加到页面。
该作法能够减小页面渲染dom元素的次数。经IE和Fx下测试,在append1000个元素时,效率能提升10%-30%,Fx下提高较为明显。
1 <script> 2 修改前: 3 for (var i = 0; i < 1000; i++) { 4 var el = document.createElement('p'); 5 el.innerHTML = i; 6 document.body.appendChild(el); 7 } 8 9 修改后: 10 var frag = document.createDocumentFragment(); 11 for (var i = 0; i < 1000; i++) { 12 var el = document.createElement('p'); 13 el.innerHTML = i; 14 frag.appendChild(el); 15 } 16 17 document.body.appendChild(frag); 18 </script>
1.2 经过模板元素clone,替代createElement
说明:经过一个模板dom对象cloneNode,效率比直接建立element高。
性能提升不明显,约为10%左右。在低于100个元素create和append操做时,没有优点。
1 <script> 2 服用前: 3 var frag = document.createDocumentFragment(); 4 for (var i = 0; i < 1000; i++) { 5 var el = document.createElement('p'); 6 el.innerHTML = i; 7 frag.appendChild(el); 8 } 9 10 document.body.appendChild(frag); 11 12 服用后: 13 var frag = document.createDocumentFragment(); 14 var pEl = document.getElementsByTagName('p')[0]; 15 for (var i = 0; i < 1000; i++) { 16 var el = pEl.cloneNode(false); 17 el.innerHTML = i; 18 frag.appendChild(el); 19 } 20 21 document.body.appendChild(frag); 22 </script>
1.3 使用一次innerHTML赋值代替构建dom元素
说明:根据数据构建列表样式的时候,使用设置列表容器innerHTML的方式,比构建dom元素并append到页面中的方式,效率有数量级上的提升。
1 <script> 2 服用前: 3 var frag = document.createDocumentFragment(); 4 for (var i = 0; i < 1000; i++) { 5 var el = document.createElement('p'); 6 el.innerHTML = i; 7 frag.appendChild(el); 8 } 9 10 document.body.appendChild(frag); 11 12 服用后: 13 var html = []; 14 for (var i = 0; i < 1000; i++) { 15 html.push('<p>' + i + '</p>'); 16 } 17 18 document.body.innerHTML = html.join(''); 19 </script>
1.4 使用firstChild和nextSibling代替childNodes遍历dom元素
说明:约能得到30%-50%的性能提升。逆向遍历时使用lastChild和previousSibling。
1 <script> 2 // 服用前: 3 var nodes = element.childNodes; 4 for (var i = 0, l = nodes.length; i < l; i++) { 5 var node = nodes; 6 …… 7 } 8 9 // 服用后: 10 var node = element.firstChild; 11 while (node) { 12 …… 13 node = node.nextSibling; 14 } 15 </script>
2.1 使用Array作为StringBuffer,代替字符串拼接的操做
说明:IE在对字符串拼接的时候,会建立临时的String对象;经测试,在IE下,当拼接的字符串愈来愈大时,运行效率会急剧降低。Fx和Opera都对字符串拼接操做进行了优化;经测试,在Fx下,使用Array的join方式执行时间约为直接字符串拼接的1.4倍。
1 <script> 2 // 服用前: 3 var now = new Date(); 4 var str = ''; 5 for (var i = 0; i < 10000; i++) { 6 str += '123456789123456789'; 7 } 8 alert(new Date() - now); 9 10 // 服用后: 11 var now = new Date(); 12 var strBuffer = []; 13 for (var i = 0; i < 10000; i++) { 14 strBuffer.push('123456789123456789'); 15 } 16 var str = strBuffer.join(''); 17 alert(new Date() - now); 18 </script>
3.1 将循环控制量保存到局部变量
说明:对数组和列表对象的遍历时,提早将length保存到局部变量中,避免在循环的每一步重复取值。
1 <script> 2 // 服用前: 3 var list = document.getElementsByTagName('p'); 4 for (var i = 0; i < list.length; i++) { 5 …… 6 } 7 8 // 服用后: 9 var list = document.getElementsByTagName('p'); 10 for (var i = 0, l = list.length; i < l; i++) { 11 …… 12 } 13 </script>
3.2 顺序无关的遍历时,用while替代for
说明:该方法能够减小局部变量的使用。比起效率优化,更能直接看到的是字符数量的优化。该作法有程序员强迫症的嫌疑。
1 <script> 2 // 服用前: 3 var arr = [1,2,3,4,5,6,7]; 4 var sum = 0; 5 for (var i = 0, l = arr.length; i < l; i++) { 6 sum += arr; 7 } 8 9 // 服用后: 10 var arr = [1,2,3,4,5,6,7]; 11 var sum = 0, l = arr.length; 12 while (l--) { 13 sum += arr[l]; 14 } 15 </script>
4.1 将条件分支,按可能性顺序从高到低排列
说明:能够减小解释器对条件的探测次数。
4.2 在同一条件子的多(>2)条件分支时,使用switch优于if
说明:switch分支选择的效率高于if,在IE下尤其明显。4分支的测试,IE下switch的执行时间约为if的一半。
4.3 使用三目运算符替代条件分支
1 <script> 2 // 服用前: 3 if (a > b) { 4 num = a; 5 } 6 else { 7 num = b; 8 } 9 9 10 // 服用后: 11 num = a > b ? a : b; 12 </script>
5.1 须要不断执行的时候,优先考虑使用setInterval
说明:setTimeout每一次都会初始化一个定时器。setInterval只会在开始的时候初始化一个定时器
1 <script> 2 //服用前: 3 var timeoutTimes = 0; 4 function timeout () { 5 timeoutTimes++; 6 if (timeoutTimes < 10) { 7 setTimeout(timeout, 10); 8 } 9 } 10 11 timeout(); 12 13 //服用后: 14 var intervalTimes = 0; 15 function interval () { 16 intervalTimes++; 17 if (intervalTimes >= 10) { 18 clearInterval(interv); 19 } 20 } 21 22 var interv = setInterval(interval, 10); 23 </script>
5.2 使用function而不是string
说明:若是把字符串做为setTimeout和setInterval的参数,浏览器会先用这个字符串构建一个function。
1 <script> 2 // 服用前: 3 var num = 0; 4 setTimeout('num++', 10); 5 6 // 服用后: 7 var num = 0; 8 function addNum () { 9 num++; 10 } 11 setTimeout(addNum, 10); 12 </script>
6.1 尽可能不使用动态语法元素
说明:eval、Function、execScript等语句会再次使用javascript解析引擎进行解析,须要消耗大量的执行时间。
6.2 重复使用的调用结果,事先保存到局部变量
说明:避免屡次取值的调用开销。
1 <script> 2 // 服用前: 3 var h1 = element1.clientHeight + num1; 4 var h2 = element1.clientHeight + num2; 5 6 // 服用后: 7 var eleHeight = element1.clientHeight; 8 var h1 = eleHeight + num1; 9 var h2 = eleHeight + num2; 10 </script>
6.3 使用直接量
说明:
var a = new Array(param,param,...) -> var a = []
var foo = new Object() -> var foo = {}
var reg = new RegExp() -> var reg = /.../
6.4 避免使用with
说明: with虽然能够缩短代码量,可是会在运行时构造一个新的scope。
OperaDev上还有这样的解释,使用with语句会使得解释器没法在语法解析阶段对代码进行优化。对此说法,没法验证。
1 <script> 2 // 服用前: 3 with (a.b.c.d) { 4 property1 = 1; 5 property2 = 2; 6 } 7 8 // 服用后: 9 var obj = a.b.c.d; 10 obj.property1 = 1; 11 obj.property2 = 2; 12 </script>
6.5 巧用||和&&布尔运算符
重要程度:★★★
1 <script> 2 // 服用前: 3 function eventHandler (e) { 4 if(!e) e = window.event; 5 } 6 7 // 服用后: 8 function eventHandler (e) { 9 e = e || window.event; 10 } 11 12 // 服用前: 13 if (myobj) { 14 doSomething(myobj); 15 } 16 17 // 服用后: 18 myobj && doSomething(myobj) 19 </script>
6.6 类型转换
说明:
1). 数字转换成字符串,应用"" + 1,性能上:("" +) > String() > .toString() > new String();
2). 浮点数转换成整型,不使用parseInt(), parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,建议使用Math.floor()或者Math.round()
3). 对于自定义的对象,推荐显式调用toString()。内部操做在尝试全部可能性以后,会尝试对象的toString()方法尝试可否转化为String。
2.1 循环引用
说明:若是循环引用中包含DOM对象或者ActiveX对象,那么就会发生内存泄露。内存泄露的后果是在浏览器关闭前,即便是刷新页面,这部份内存不会被浏览器释放。
1 <script> 2 // 简单的循环引用: 3 var el = document.getElementById('MyElement'); 4 var func = function () {…} 5 el.func = func; 6 func.element = el; 7 8 // 可是一般不会出现这种状况。一般循环引用发生在为dom元素添加闭包做为expendo的时候。 9 // 如: 10 function init() { 11 var el = document.getElementById('MyElement'); 12 el.onclick = function () {……} 13 } 14 init(); 15 </script>
init在执行的时候,当前上下文咱们叫作context。这个时候,context引用了el,el引用了function,function引用了context。这时候造成了一个循环引用。
下面2种方法能够解决循环引用:
1) 置空dom对象
1 <script> 2 // 服用前: 3 function init() { 4 var el = document.getElementById('MyElement'); 5 el.onclick = function () {……} 6 } 7 8 init(); 9 10 // 服用后: 11 function init() { 12 var el = document.getElementById('MyElement'); 13 el.onclick = function () {……} 14 el = null; 15 } 16 17 init(); 18 19 将el置空,context中不包含对dom对象的引用,从而打断循环应用。 20 若是咱们须要将dom对象返回,能够用以下方法: 21 // 服用前: 22 function init() { 23 var el = document.getElementById('MyElement'); 24 el.onclick = function () {……} 25 return el; 26 } 27 28 init(); 29 30 // 服用后: 31 function init() { 32 var el = document.getElementById('MyElement'); 33 el.onclick = function () {……} 34 try{ 35 return el; 36 } 37 finally { 38 el = null; 39 } 40 } 41 42 init(); 43 </script>
2) 构造新的context
1 <script> 2 // 服用前: 3 function init() { 4 var el = document.getElementById('MyElement'); 5 el.onclick = function () {……} 6 } 7 8 init(); 9 10 // 服用后: 11 function elClickHandler() {……} 12 function init() { 13 var el = document.getElementById('MyElement'); 14 el.onclick = elClickHandler; 15 } 16 17 init(); 18 19 把function抽到新的context中,这样,function的context就不包含对el的引用,从而打断循环引用。 20 </script>
2.2 经过javascript建立的dom对象,必须append到页面中
说明:IE下,脚本建立的dom对象,若是没有append到页面中,刷新页面,这部份内存是不会回收的!
1 <script> 2 // 示例代码: 3 function create () { 4 var gc = document.getElementById('GC'); 5 for (var i = 0; i <5000; i++) { 6 var el = document.createElement('div'); 7 el.innerHTML = "test"; 8 // 下面这句能够注释掉,看看浏览器在任务管理器中,点击按钮而后刷新后的内存变化 9 gc.appendChild(el); 10 } 11 } 12 </script>
2.3 释放dom元素占用的内存
说明:
将dom元素的innerHTML设置为空字符串,能够释放其子元素占用的内存。
在rich应用中,用户也许会在一个页面上停留很长时间,可使用该方法释放积累得愈来愈多的dom元素使用的内存。
2.4 释放javascript对象
说明:在rich应用中,随着实例化对象数量的增长,内存消耗会愈来愈大。因此应当及时释放对对象的引用,让GC可以回收这些内存控件。
对象:obj = null
对象属性:delete obj.myproperty
数组item:使用数组的splice方法释放数组中不用的item
2.5 避免string的隐式装箱
说明:对string的方法调用,好比'xxx'.length,浏览器会进行一个隐式的装箱操做,将字符串先转换成一个String对象。推荐对声明有可能使用String实例方法的字符串时,采用以下写法:
var myString = new String('Hello World');