码迷,mamicode.com
首页 > 编程语言 > 详细

Javascript 优化

时间:2015-07-24 16:19:46      阅读:194      评论:0      收藏:0      [点我收藏+]

标签:

  • createDocumentFragment的使用
  • 首先,介绍了几种常见的动态创建html节点的方法,如下所示:
    方法 说明
    crateAttribute(name) 用指定名称name创建特性节点
    createComment(text) 创建带文本text的注释节点
    createDocumentFragment() 创建文档碎片节点
    createElement(tagname) 创建标签名为tagname的节点
    createTextNode(text) 创建包含文本text的文本节点

    以上这些方法,每次JavaScript对DOM的操作都会改变当前页面的呈现,并重新刷新整个页面,从而消耗了大量的时间。为解决这个问题,可以创建一个文档碎片,把所有的新节点附加其上,然后把文档碎片的内容一次性添加到document中,这个就是createDocumentFragment()的用武之处。

    createDocumentFragment()说明

    DocumentFragment:表示文档的一部分(或一段),更确切地说,它表示一个或多个邻接的 Document 节点和它们的所有子孙节点。

    DocumentFragment 节点不属于文档树,继承的 parentNode 属性总是 null。

    不过它有一种特殊的行为,该行为使得它非常有用,即当请求把一个DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。这使得 DocumentFragment 成了有用的占位符,暂时存放那些一次插入文档的节点。它还有利于实现文档的剪切、复制和粘贴操作。

    可以用Document.createDocumentFragment() 方法创建新的空 DocumentFragment 节点。

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

    createDocumentFragment()用法示例

    使用appendChild逐个向DOM文档中添加1000个新节点:
    for (var i = 0; i < 1000; i++)
    {
        var el = document.createElement(‘p‘);
        el.innerHTML = i;
        document.body.appendChild(el);
    }

    使用createDocumentFragment()一次性向DOM文档中添加1000个新节点:
    var frag = document.createDocumentFragment();
    for (var i = 0; i < 1000; i++)
    {
        var el = document.createElement(‘p‘);
        el.innerHTML = i; frag.appendChild(el);
    }
    document.body.appendChild(frag);

    不要小瞧这10%-30%,效率的提高是着眼于多个细节的,如果我们能在很多地方都能让程序运行速度提高10%-30%,那将是一个质的飞跃,您也将步入骨灰级玩家的行列。

 

  • 优化JS中的条件分支语句

一、将条件分支,按可能性顺序从高到低排列

说明:可以减少解释器对条件的探测次数。

二、在同一条件子的多(>2)条件分支时,使用switch优于if

说明:switch分支选择的效率高于if,在IE下尤为明显。4分支的测试,IE下switch的执行时间约为if的一半。

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

使用前:
if (a > b)
{ num = a; }
else
{ num = b; }

使用后:
num = a > b ? a : b;

 

  • JS循环引用的内存泄露问题

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

    简单的循环引用:
    var el = document.getElementById(‘MyElement‘);
    var func = function () {…}
    el.func = func;
    func.element = el;

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

    如:
    function init()
    {
        var el = document.getElementById(‘MyElement‘);
        el.onclick = function () {……}
    }
    init();

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

    下面2种方法可以解决循环引用

    • 置空dom对象
      使用前:
      function init()
      {
          var el = document.getElementById(‘MyElement‘);
          el.onclick = function () {……}
      }
      init();

      使用后:
      function init()
      {
          var el = document.getElementById(‘MyElement‘);
          el.onclick = function () {……}
          el = null;
      }
      init();

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

      使用前:
      function init()
      {
          var el = document.getElementById(‘MyElement‘);
          el.onclick = function () {……}
          return el;
      }
      init();

      使用后:
      function init()
      {
          var el = document.getElementById(‘MyElement‘);
          el.onclick = function () {……}
          try{ return el; }
          finally { el = null; }
      }
      init();
       
    • 构造新的context
      使服用前:
      function init()
      {
          var el = document.getElementById(‘MyElement‘);
          el.onclick = function () {……}
      }
      init();

      使用后:
      function elClickHandler() {……}
      function init() {
          var el = document.getElementById(‘MyElement‘);
          el.onclick = elClickHandler;
      }
      init(); 把function抽到新的context中,这样,function的context就不包含对el的引用,从而打断循环引用。

 

  • Javascript中声明变量速度的研究

    声明变量到底要不要var

    • 使用var语句多次声明一个变量不仅是合法的,而且也不会造成任何错误。
    • 如果重复使用的一个声明有一个初始值,那么它担当的不过是一个赋值语句的角色。
    • 如果重复使用的一个声明没有一个初始值,那么它不会对原来存在的变量有任何的影响。

    没有var声明的变量,是作为全局变量存在的;有var声明的变量,属于局部变量,尤其是在函数内部。并且,经过测试,带var声明比不带var速度要快,比如:"var a"比"a"具有更快的执行速度。我们有理由推测,局部变量的声明比全局变量的声明效率更高。

    直接量与new

    变量有好几种类型,但是同一类型的变量创建的方式可能不一样,比如string、Object、Array等这些类型的变量声明或者创建。

    经过测试,通过直接量声明的速度明显快于通过new声明的速度,比如"var a={} "比"var a=new Object()"具有更快的执行速度。

    局部变量与全局变量

    现在笔者来告诉你,函数内尽量多设局部变量,这样即安全又快速,变量操作也更加合理,不会因为函数内胡乱操作全局变量而导致逻辑错误。

    写个例子说明下,先建立一个全局变量:var m=1; ,接着我读取这个全局变量1000000次

    全局变量:
    for(var i=1000000;i--;)
    {a=m;}

    局部变量:
    (function (){
        var n=m;
        for(var i=1000000;i--;)
        {a=n;}
    })();

    执行速度2>1

    通过上面测试表明,先将m这个全局变量的值存给局部变量n,在将n赋值给a具有更快的速度。

    变量名长度

    变量名是自己取的,为了照顾语义和规范,变量名可能稍长,但是注意了,变量名的长度也会影响代码的执行速度。

    经过测试,长的变量名声明的执行速度没有短的快,比如"var a=1"比"var aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=1"具有更快的执行速度。

    所以,我们在声明变量的时候,尽量缩写一些单词,并记忆一些常见的缩写,以下是缩写示例:
    单词 缩写
    array(数组) arr
    string(字符串) str
    number(数量/数字) num
    function(函数) fun
    message(消息/信息) mes
    userNumber(会员数量) userNum/uNum
    parentElement(父级节点/父级元素) parentEle
    returnArray(返回的数组) returnArr

 

 

  • JS全局变量的副作用

    JavaScript通过函数管理作用域。局部变量是在函数内部使用 var 声明的变量;全局变量则会在下列情况下出现:
    1. 在任何地方不使用 var 声明变量,或者直接向未声明的变量赋值。
    2. 在函数外部使用 var 声明的变量。
    3. 以 window. variable 形式声明的变量。

    全局变量的问题在于,你的JavaScript应用程序和web页面上的所有代码都共享了这些全局变量,他们住在同一个全局命名空间,所以当程序的两个不同部分定义同名但不同作用的全局变量的时候,命名冲突在所难免。

    web页面包含不是该页面开发者所写的代码也是比较常见的,例如:
    • 第三方的JavaScript库
    • 广告方的脚本代码
    • 第三方用户跟踪和分析脚本代码
    • 不同类型的小组件,标志和按钮

    比方说,该第三方脚本定义了一个全局变量,叫做result;接着,在你的函数中也定义一个名为result的全局变量。其结果就是后面的变量覆盖前面的,第三方脚本就一下子嗝屁啦!

    因此,要想和其他脚本成为好邻居的话,应该尽可能少的使用全局变量,并且始终使用var来声明变量。

    以下是几种常见的误将局部变量声明为全局变量的例子。

    一、函数内部不使用 var 声明变量
    function sum(x, y) {
       // 不推荐写法: 隐式全局变量
       result = x + y;
       return result;
    }

    此段代码中的result没有声明。代码照样运作正常,但在调用函数后你最后的结果就多一个全局命名空间,这可以是一个问题的根源。

    经验法则是始终使用var声明变量,正如改进版的sum()函数所演示的:

    function sum(x, y) {
       var result = x + y;
       return result;
    }

    二、使用任务链进行部分 var 声明

    // 反例,勿使用
    function foo() {
       var a = b = 0;
       // ...
    }

    上面的片段中,a是本地变量但是b确实全局变量,这可能不是你希望发生的。

    此现象发生的原因在于这个从右到左的赋值,首先,是赋值表达式b = 0,此情况下b是未声明的。这个表达式的返回值是0,然后这个0就分配给了通过var定义的这个局部变量a。换句话说,就好比你输入了:
        var a = (b = 0);
    如果你已经准备好声明变量,使用链分配是比较好的做法,不会产生任何意料之外的全局变量,如:
    function foo() {
       var a, b;
       // ... a = b = 0; // 两个均局部变量
    }

    IT学苑提示隐式全局变量和明确定义的全局变量间有些小的差异,就是通过delete操作符让变量未定义的能力:
    • 通过var创建的全局变量(任何函数之外的程序中创建)是不能被删除的。
    • 无var创建的隐式全局变量(无视是否在函数中创建)是能被删除的。
    这表明,在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性。属性是可以通过delete操作符删除的,而变量是不能的。

    使用即时函数函数,避免变量污染

    为了避免全局的变量的污染,IT学苑推荐一种即时函数的写法,即将具有独立功能的代码放在一个即时函数里面。如下:
    (function(){
        //输出变量 itxueyuan
        var itxueyuan="http://www.itxueyuan.com/javascript/";
        document.write(itxueyuan+"<br />");
    })();

    document.write(itxueyuan);

    结果,第一次输出http://www.itxueyuan.com/javascript/,第二次提示语法错误:
    技术分享

    可见,变量itxueyuan的作用域仅限于及即时函数内部,有效避免了变量的污染,尤其是在引入第三方代码的情况下。由于IT学苑的JS代码很大一部分使用了这种模式,有效避免了变量冲突。

 

Javascript 优化

标签:

原文地址:http://my.oschina.net/u/242764/blog/483361

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!