JS一些類實現方式的效能研究

來源:互聯網
上載者:User
文章目錄
  • 實現1
  • 實現2
  • 實現3
  • 實現4
  • 實現5
  • 實現6
  • 實現7
  • 實現8
  • 實現9
  • 實現10
  • 實現11

從javaeye看到一貼,探討如何?計時器,集思廣益,最後竟然提出了十多種的實現。這再次證明了JS的寫法很靈活(舉個反面的例子,如Python,其哲學原則是one way to go!)。這裡整理一下,研究一下各種實現的效能問題。現在JS越來越向富用戶端發展,UI組件乃至網頁遊戲,對效能問題是相當重視的。

實現1
  function Timer(id){    this.id = id;    this.begin = function(count){      this.show(this.id, count)();      setInterval(this.show(this.id, count-1),1000);    }    this.show = function(id, count){      return function(){        document.getElementById(id).innerHTML = count < 0 ? "over" :count;        count--;      }    }  }

time1time2

開始

點評:採用最經典的建構函式來實作類別。好處是明快易懂,缺點是多個執行個體都是獨立的記憶體,資料與方法都不共用。而且還存在一個明顯的缺陷,計時完成之後,setInterval沒有被clear,嚴重影響了效能。

實現2
function Timer(id){    this.id = id;    this.timer = null;    this.count = 0;    this.begin = function(count){        this.count = count;        this.show(this)();        this.timer = setInterval(this.show(this),1000);    }    this.show = function(obj){        return function(){            if(obj.count < 0){                document.getElementById(obj.id).innerHTML = "over";                clearInterval(obj.timer);                return ;            }            document.getElementById(obj.id).innerHTML = obj.count;            obj.count--;        }    }}

time1time2

開始

點評:解決了實現1的setInterval未被clear的問題,但依然是利用建構函式來實作類別,因此Timer每個執行個體都複製了一份show和begin,而不是共用同一份。

實現3
function Timer(id){    this.id = id;    this.timer = null;      this.count = 0;    this.begin = function(count){        this.count = count;        Timer.show(this)();        this.timer = setInterval(Timer.show(this),1000);    }    Timer.show = function(obj){        return function(){            if(obj.count   time1  time2

開始

點評:把show()弄成類的靜態方法,讓所有執行個體共用此方法。注意,show()是個currying函數,這就解決了各執行個體的資料互相汙染的問題。

實現4
function Timer(id){    this.id = id;    this.timer = null;    this.count = 0;    this.begin = function(count){        this.count = count;        this.show(this)();//注意和實現三的區別:這裡不是Timer.show(this)();        this.timer = setInterval(this.show(this),1000);//注意和實現三的區別:這裡不是Timer.show(this)();    }}Timer.prototype.show = function(obj){    return function(){        if(obj.count < 0){            document.getElementById(obj.id).innerHTML = "over";            clearInterval(obj.timer);            return ;        }        document.getElementById(obj.id).innerHTML = obj.count;        obj.count--;    }}  

time1time2

開始

點評:這次把show()做成原型方法,由於所有執行個體都是共用原型,當執行個體在其成員中找不到此方法,它就會沿著原型鏈往上找。這個運用了很經典的類實現方式——混合的建構函式 /原型方式。

實現5
function Timer(id){    this.id = id;    this.timer = null;    this.count = 0;}Timer.prototype.begin = function(count){    this.count = count;    this.show(this)();//注意這裡不是Timer.show(this)();    this.timer = setInterval(this.show(this),1000);//注意這裡不是Timer.show(this)();}Timer.prototype.show = function(obj){    return function(){        if(obj.count   time1  time2

開始

點評:這次把bigin()也做成原型方法。

實現6
function Timer(id){      this.id = id;      this.timer = null;      this.count = 0;  }  Timer.prototype = {      begin : function(count){          this.count = count;          this.show(this)();//注意這裡不是Timer.show(this)();          this.timer = setInterval(this.show(this),1000);//注意這裡不是Timer.show(this)();      },      show : function(obj){             return function(){              if(obj.count < 0){                  document.getElementById(obj.id).innerHTML = "over";                  clearInterval(obj.timer);                  return ;              }              document.getElementById(obj.id).innerHTML = obj.count;              obj.count--;          }      }   } 

time1time2

開始

點評:把原型方法整到一個對象中去。

實現7
function Timer(id){      this.id = id;      this.timer = null;      this.count = 0;      Timer.prototype.begin = function(count){          this.count = count;          this.show(this)();//主要這裡不是Timer.show(this)();          this.timer = setInterval(this.show(this),1000);//主要這裡不是Timer.show(this)();      }      Timer.prototype.show = function(obj){             return function(){              if(obj.count   time1  time2

開始

點評:把原型方法整到建構函式中去,但千萬不要弄成這個樣子:

function Timer(id){    this.id = id;    this.timer = null;    this.count = 0;    Timer.prototype= {        begin:function(count){/*……*/},        show : function(obj){ /*……*/}    }} 

因為直接為prototype 賦值,會使得自動添加的 constructor 成員丟失!

實現8
var Timer = {    begin : function(id,count){        var obj = {};        obj["id"] = id;        obj["count"] = count;        Timer.show(obj)();        obj["timer"] = setInterval(Timer.show(obj),1000);//注意這裡不是Timer.show(this)();    },    show : function(obj){        return function(){            if(obj["count"] < 0){                document.getElementById(obj["id"]).innerHTML = "over";                clearInterval(obj["timer"]);                return ;            }            document.getElementById(obj["id"]).innerHTML = obj["count"] ;            obj["count"]--;        }    }}

time1time2

開始

點評:這次採用字面量構造對象。Timer成了一個全域對象(當我們第一次調用begin方法才產生此全域對象),類似於window,產生執行個體方法不再是new,而是採用工廠方式的方法,每begin一次就產生一個執行個體,資料是獨立的,方法是共用的。

實現9
var Timer = (function(){    var items = {};    function begin(id,count){        var obj = {};        obj["id"] = id;        obj["count"] = count;        Timer.show(obj)();        obj["timer"] = setInterval(Timer.show(obj),1000);//注意這裡不是Timer.show(this)();        Timer.items[id] = obj;    };    function show(obj){        return function(){            if(obj["count"]   time1  time2

開始

點評:利用閉包,和上面的有點類似,但此全域變數是DOM樹完成後就立即產生的,它擁有以下三個方法items : begin 與 show。許多類庫也採用此方式實現,不過它們稱之為命名空間而已……

實現10
function Timer(id){    this.element = document.getElementById(id);    this.timer = null;    this.count = 0;}Timer.prototype = {    begin : function(count){        this.count = count;        this.show();        var _this = this;        this.timer = setInterval(function(){_this.show();}, 1000);    }    ,    show : function(){        this.element.innerHTML = this.count < 0 ? clearInterval(this.timer) || "over" : this.count--;    }}

time1time2

開始

點評:這是實現3的改進版,改進了每調用一次show就遍曆DOM樹的缺點(document.getElementById),而是第一次找到的元素放入執行個體的成員。利用三元運算式與短路運算使得代碼更加內斂。儲存this,免去每次都往上層的範圍尋找。

實現11
function Timer(id) {    this.container = document.getElementById(id);}Timer.prototype = {    constructor: Timer,    begin: function(count) {        var container = this.container;        setTimeout(function() {            container.innerHTML = count > 0 ? count-- : "over";            if(count + 1) {                setTimeout(arguments.callee, 1000);            }        }, 1000);    }};

time1time2

開始

點評:YUI風格的實現方式,該類庫大量使用arguments ,callee等內部屬性。現在Timer類的成員很小,內部私人屬性也很少,效能明顯比以上所有實現要好得多。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.