代码、复制-Javascript执行效率小结-by小雨

新手发帖,很多方面都是刚入门,有错误的地方请大家见谅,欢迎批评指正

    Javascript是一门非常活灵的言语,我们可以欲所心随的誊写各种格风的代码,不同格风的代码也必定也会致导执行率效的差异,发开中程过零零散散地接触到多许进步代码性能的方法,理整一下平常比拟见常并且轻易规避的问题

    

Javascript自身执行率效

    Javascript中的用作域链、闭包、原型继承、eval等性特,在供提各种奇异功能的同时也带来了各种率效问题,用之慎不就会致导执行率效低下。

    

1、全局入导

    我们在编码中程过多多少少会应用到一些全局变量(window,document,自义定全局变量等等),懂得javascript用作域链的人都道知,在局部用作域中拜访全局变量要需一层一层遍历全部用作域链直至顶级用作域,而局部变量的拜访率效则会更快更高,因此在局部用作域中高频率应用一些全局对象时可以将其入导到局部用作域中,例如:

复制代码
 1 //1、作为参数传入模块
 2 (function(window,$){
 3     var xxx = window.xxx;
 4     $("#xxx1").xxx();
 5     $("#xxx2").xxx();
 6 })(window,jQuery);
 7 
 8 //2、暂存到局部变量
 9 function(){
10     var doc = document;
11     var global = window.global;
12 }
复制代码

2、eval以及类eval问题

    我们都道知eval可以将一段字符串做当js代码来执行理处,据说应用eval执行的代码比不应用eval的代码慢100倍以上(详细率效我没有测试,有兴致学同可以测试一下)

    

    JavaScript 代码在执行前会停止似类“预编译”的作操:首先会创立一个前当执行境环下的动活对象,并将那些用 var 声名的变量置设为动活对象的属性,但是此时这些变量的赋值都是 undefined,并将那些以 function 义定的函数也添加为动活对象的属性,而且它们的值是正函数的义定。但是,如果你应用了“eval”,则“eval”中的代码(实际上为字符串)没法事后识别其上下文,没法被前提剖析和化优,即没法停止预编译的作操。所以,其性能也会大幅度下降

    

    其实当初大家一般都很少会用eval了,这里我想说的是两个类eval的场景(new Function{},setTimeout,setInterver)

复制代码
setTimtout("alert(1)",1000);

setInterver("alert(1)",1000);

(new Function("alert(1)"))();
复制代码

上述几种类型代码执行率效会都比拟低,因此提议直接传入匿名方法、或者方法的引用给setTimeout方法

    

3、闭包束结后放释掉不再被引用的变量

复制代码
var f = (function(){
    var a = {name:"var3"};
    var b = ["var1","var2"];
    var c = document.getElementByTagName("li");
    //****其它变量
    //***一些运算
    var res = function(){
        alert(a.name);
    }
    return res;
})()
复制代码

上述代码中变量f的返回值是由一个即立执行函数成构的闭包中返回的方法res,该变量保留了对于这个闭包中有所变量(a,b,c等)的引用,因此这两个变量会始终驻留在内存空间中,尤其是对于dom素元的引用对内存的消费会很大,而我们在res中只应用到了a变量的值,因此,在闭包返回前我们可以将其它变量放释

复制代码
var f = (function(){
    var a = {name:"var3"};
    var b = ["var1","var2"];
    var c = document.getElementByTagName("li");
    //****其它变量
    //***一些运算
    //闭包返回前放释掉不再应用的变量
    b = c = null;
    var res = function(){
        alert(a.name);
        }
    return res;
})()
复制代码

Js作操dom的率效

    在web发开中程过,前端执行率效的瓶颈往往都是在dom作操上面,dom作操是一件很耗性能的事件,如何才能在dom作操中程过尽量约节性能呢?

    

1、少减reflow

    

什么是reflow?

    

    当 DOM 素元的属性产生变更 (如 color) 时, 浏览器会通知 render 从新描写响应的素元, 此程过称为 repaint。

    如果该次变更及涉素元局布 (如 width), 浏览器则摈弃原有属性, 从新盘算并把结果传递给 render 以从新描写面页素元, 此程过称为 reflow。

    

    

少减reflow的方法

    

  1. 先将素元从document中删除,成完修改后再把素元放回本来的置位(当对某素元及其子素元停止量大reflow作操时,1,2两种方法果效才会比拟显著)

  2. 将素元的display置设为”none”,成完修改后再把display修为改本来的值

  3. 修改多个式样属性时义定class类取代多次修改style属性(for certain学同推荐)
  4. 量大添加素元到面页时应用documentFragment

    例如

复制代码
for(var i=0;i<100:i++){
    var child = docuemnt.createElement("li");
    child.innerHtml = "child";
    document.getElementById("parent").appendChild(child);
}
复制代码

上述代码会多次作操dom,率效比拟低,可以为改上面的式形 创立documentFragment,将有所素元参加到docuemntFragment不会转变dom结构,最后将其添加到面页,只停止了一次reflow

复制代码
var frag = document.createDocumentFragment();
for(var i=0;i<100:i++){
        var child = docuemnt.createElement("li");
        child.innerHtml = "child";
    frag.appendChild(child);
}
document.getElementById("parent").appendChild(frag);
复制代码

2、暂存dom态状息信

    当代码中要需多次拜访素元的态状息信,在态状变不的情况下我们可以将其暂存到变量中,这样可以防止多次拜访dom带来内存的开销,型典的例子就是:

复制代码
var lis = document.getElementByTagName("li");
for(var i=1;i<lis.length;i++){
    //***
}
上述式方会在每一次环循都去拜访dom素元,我们可以简略将代码化优如下
var lis = document.getElementByTagName("li");
for(var i=1,j=lis.length ;i<j;i++){
    //***
}
复制代码

3、小缩选择器的查找围范

    查找dom素元时尽量防止大面积遍历面页素元,尽量应用精准选择器,或者指定上下文以小缩查找围范,以jquery为例

    

  • 用少模糊匹配的选择器:例如$("[name*='_fix']"),多用诸如id以及逐渐小缩围范的复合选择器$("li.active")
  • 指定上下文:例如$("#parent .class")$(".class",$el)

    

4、应用事件委托

    应用场景:一个有量大记载的表列,每条记载都要需定绑点击事件,在标鼠点击后实现某些功能,我们平日的做法是给每条记载都定绑听监事件,种这做法会致导面页会有量大的事件听监器,率效比拟低下。

    基本理原:我们都道知dom范规中事件是会冒泡的,也就是说在不动主阻挠事件冒泡的情况下任何一个素元的事件会都按照dom树的结构逐级冒泡至顶端。而event对象中也供提了event.target(IE下是srcElement)指向事件源,因此我们即使在父级素元上听监该事件也可以找到触发该事件的最原始的素元,这就是委托的基本理原。话废不多说,上示例

$("ul li").bind("click",function(){
    alert($(this).attr("data"));
})

上述写法是实其给有所的li素元都定绑了click事件来听监标鼠点击个一每素元的事件,这样面页上会有量大的事件听监器。

    根据上面绍介的听监事件的理原我们来改写一下

复制代码
$("ul").bind("click",function(e){
    if(e.target.nodeName.toLowerCase() ==="li"){
        alert($(e.target).attr("data"));
    }
})
复制代码

这样一来,我们以可就只添加一个事件听监器去获捕有所li上触发的事件,并做出响应的作操。

    当然,我们不必每次都做事件源的判断任务,可以将其抽象一下交给具工类来成完。jquery中的delegate()方法就实现了该功能

    语法是这样的$(selector).delegate(childSelector,event,data,function),例如:

$("div").delegate("button","click",function(){
  $("p").slideToggle();
});

    参数说明(引自w3school)

    

    

参数 描述
childSelector 必须。划定要附加事件理处程序的一个或多个子素元。
event

必须。划定附加到素元的一个或多个事件。由空格隔分多个事件值。必须是有效的事件。

data 可选。划定传递到函数的额定数据。
function 必须。划定当事件产生时运行的函数。

    Tips:事件委托还有一个利益就是,即使在事件定绑后之动态添加的素元上触发的事件样同可以听监到哦,这样就不用在每次动态参加素元到面页后都为其定绑事件了

    临时先总结到这

文章结束给大家分享下程序员的一些笑话语录: 爱情观
  爱情就是死循环,一旦执行就陷进去了。
  爱上一个人,就是内存泄露--你永远释放不了。
  真正爱上一个人的时候,那就是常量限定,永远不会改变。
  女朋友就是私有变量,只有我这个类才能调用。
  情人就是指针用的时候一定要注意,要不然就带来巨大的灾难。

你可能感兴趣的:(JavaScript)