zoukankan      html  css  js  c++  java
  • JS一些类实现方式的性能研究

    从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--;
          }
        }
      }

    time1
    time2
    开始

    点评:采用最经典的构造函数来实现类。好处是明快易懂,缺点是多个实例都是独立的内存,数据与方法都不共享。而且还存在一个明显的缺陷,计时完成之后,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--;
            }
        }
    }

    time1
    time2
    开始

    点评:解决了实现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 < 0){
                    document.getElementById(obj.id).innerHTML = "over";
                    clearInterval(obj.timer);
                    return ;
                }
                document.getElementById(obj.id).innerHTML = obj.count;
                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--;
        }
    }  

    time1
    time2
    开始

    点评:这次把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 < 0){
                document.getElementById(obj.id).innerHTML = "over";
                clearInterval(obj.timer);
                return ;
            }
            document.getElementById(obj.id).innerHTML = obj.count;
            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--;  
            }  
        }   


    time1
    time2
    开始

    点评:把原型方法整到一个对象中去。

    实现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 < 0){  
                    document.getElementById(obj.id).innerHTML = "over";  
                    clearInterval(obj.timer);  
                    return ;  
                }  
                document.getElementById(obj.id).innerHTML = obj.count;  
                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"]--;
            }
        }
    }

    time1
    time2
    开始

    点评:这次采用字面量构造对象。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"] < 0){
                    document.getElementById(obj["id"]).innerHTML = "over";
                    clearInterval(obj["timer"]);
                    return ;
                }
                document.getElementById(obj["id"]).innerHTML = obj["count"] ;
                obj["count"]--;
            }
        }
        return {
            items : items,
            begin : begin,
            show : show
        }
    })()

    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--;
        }
    }

    time1
    time2
    开始

    点评:这是实现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);
        }

    };

    time1
    time2
    开始

    点评:YUI风格的实现方式,该类库大量使用arguments ,callee等内部属性。现在Timer类的成员很小,内部私有属性也很少,性能明显比以上所有实现要好得多。
  • 相关阅读:
    rails6 导入js依赖库css样式
    close yarn install --check-files
    常用gem
    upgrade rubygems
    test String.split
    解决在manjaro下,vscode无法将chrome作为默认浏览器打开
    Lyrics of the song 99 Bottles of Beer
    C#WebBrowser控件使用教程与技巧收集
    Android学习:ActionBar活动条
    Android学习:AlertDialog对话框
  • 原文地址:https://www.cnblogs.com/aaa6818162/p/2681236.html
Copyright © 2011-2022 走看看