JavaScript设计模式

1、JavaScript实现接口

  方法1:注释

    //interface Composite{
    //    function add(obj);
    //    function remove(obj);
    //    function update(obj);
    //}
    
    //CompositeImpl必须实现add remove update 3个方法
    function CompositeImpl(){}
    CompositeImpl.prototype.add=function(obj){};
    CompositeImpl.prototype.remove=function(obj){};
    CompositeImpl.prototype.update=function(obj){};
    
    var c1 = new CompositeImpl();
    var c2 = new CompositeImpl();

  方法2:属性检测

    function CompositeImpl(){
        //显式的在类的内部接受所实现的接口
        //一般来说在类的内部要定义一个变量,接收实现接口的名字
        this.implementsInterface = ["Composite","FormItem"];
    }
    CompositeImpl.prototype.add=function(obj){};
    CompositeImpl.prototype.remove=function(obj){};
    CompositeImpl.prototype.update=function(obj){};
    CompositeImpl.prototype.select=function(obj){};
    //检测函数
    function CheckCompositeImpl(instance){
        //判断当前对象是否实现了所有的接口
        if(!IsImplements(instance,"Composite","FormItem")){
            throw new Error("没有实现所有的方法");
        }
    }
    //公用的具体的检测方法 核心方法
    function IsImplements(obj){
        for(var i=1;i<arguments.length;i++){
            var interfaceName = arguments[i];
            var interfaceFound = false;
            for(var j=0;j<obj.implementsInterface.length;j++){
                if(obj.implementsInterface[j] == interfaceName){
                    interfaceFound=true;
                    break;
                }
            }
            if(!interfaceFound){
                return false;
            }
        }
        return true;
    }
    
    var c1=new CompositeImpl();
    CheckCompositeImpl(c1);

  方法3:鸭式辩型

    类实现接口的目的就是要把接口里面所有的方法都实现

    鸭式辩型核心的核心就是检测方法

   //1、接口类 用来实例化接口
    //需要两个参数 1、接口名字 2、方法名数组
    function Interface(name,methods){
        if(arguments.length != 2){
            throw new Error("该接口实例化对象构造函数参数不是2");
        }
        this.name = name;
        this.method = [];
        
        for(var i=0,len=methods.length;i<len;i++){
            if(typeof methods[i] !== “string”){
                throw new Error("接口方法名不是string类型");
            }
            this.methods.push(methods[i]);
        }
    }
    Interface.ensureImplements = function(obj){
        if(arguments.length < 2){
            throw new Error("ensureImplements参数个数为"+arguments.length+",不符合要求");
        }
        
        for(var i=1;i<arguments.length;i++){
            var instanceInterface = arguments[i];
            if(instanceInterface.constructor !== Interface){
                throw new Error("参数类型不是Interface接口类型");
            }
            for(var j=0;j<instanceInterface.methods.length;j++){
                var methodName=instanceInterface.methods[j];
                if(!obj[methodName] || typeof object[methodName]!="function"){
                    throw new Error(methodName+"方法没有实现或者不是函数类型");
                }
            }
        }
    };
    
    
    function CompositeImpl(){
        
    }
    CompositeImpl.prototype.add=function(obj){};
    CompositeImpl.prototype.remove=function(obj){};
    CompositeImpl.prototype.update=function(obj){};
    CompositeImpl.prototype.select=function(obj){};    
    
    var CompositeInterface = new Interface("CompositeInterface",["add","remove"]);
    var FormItemInerface = new Interface("FormItemInerface",["update","select"]);
    
    var c1 = new CompositeImpl();
    Interface.ensureImplements(c1,CompositeInterface,FormItemInerface);

2、单体模式

    //简单单体
    var Singleton={
        attr1:true,
        attr2:10,
        method1:function(){
            alert("方法一");
        },
        method2:function(){
            alert("方法二");
        }
    };
    alert(Singleton.attr1);    
    //借助闭包创建单体 闭包的主要目的是保护数据 拥有自己的作用域
    var BHX={};
    BHX.Singleton=(function(){
        //在这个作用域里面可以添加自己的成员
        var a1=true;
        var a2=10;
        function f1(){
            alert("f1");
        }
        function f2(){
            alert("f2");
        }
        
        return {
            attr1:a1,
            attr2:a2,
            method1:f1,
            method2:f2
        };
    })();
alert(BHX.Singleton.attr1);
//惰性单体 和闭包单体有一些相似的地方
    var Ext={};
    Ext.Base=(function(){
        var uniqInstance;
        
        function init(){
            var a1=10;
            var a2=true;
            var fn1=function(){alert("fn1");};
            var fn2=function(){alert("fn2");};

            return {
                attr1:a1,
                attr2:a2,
                method1:fn1,
                method2:fn2
            };
        }
        
        return {
            getInstance:function(){
                if(!uniqInstance){
                    uniqInstance=init();
                }
                return uniqInstance;
            },
        };
    })();
    alert(Ext.Base.getInstance().attr1);
//分支单体 判断程序的分支 和switch类似
    var Ext={};
    var diff=true;
    Ext.More=(function(){
        var objA={
            attr1:"FF"
        };
        var objB={
            attr1:"IE"
        };
        return def ? objA : objB;
    })();
    alert(Ext.More.attr1);

3、函数链式调用

    function Dog(){
        this.run=function(){
            alert("Dog is running");
            return this;
        };
        this.eat=function(){
            alert("Dog is eating");
            return this;
        };
        this.sleep=function(){
            alert("Dog is sleeping");
            return this;
        };
    }
    var d1=new Dog();
    d1.run();
    d1.sleep();
    d1.eat();
    //==================jquery模拟
    (function(){
        function _$(arguments){
            var idSel=/^#w+/;
            this.dom;
            
            if(idSel.test(arguments[0])){
                this.dom=document.getElementById(arguments[0].substring(1));
            }else{
                throw new Error("无法匹配id");
            }
        }
        
        Function.prototype.method=function(methodName,fn){
            this.prototype[methodName]=fn;
            return this;
        };
        
        _$.prototype={
            constructor:_$,
            addEvent:function(){},
            setStyle:function(){}
        };
        
        _$.onReady=function(fn){
            window.$=function(){
                return new _$(arguments);
            };
            fn();
            _$.method("addEvent",function(){
                return this;
            }).method("setStyle",function(){
                return this;
            });
        };
        
        window.$=_$;
    })(window);
    
    $.onReady(function(){
        $("#inp")
    });

4、工厂方式

    function CarShop(){
        
    }
    CarShop.prototype={
        constructor:CarShop,
        sellCar:function(type){
            var car=CarFactory.createCar(type);
            return car;
            //这是生产车的逻辑,所以不应该出现在这里
            //var car;
            //switch(type){
            //    case "Benz":
            //        car=new Benz();
            //        break;
            //    case "Bmw":
            //        car=new Bmw();
            //        break;
            //    case "Audi":
            //        car=new Audi();
            //        break;
            //    default:
            //        "没有合适的车";
            //}
            //Interface.ensureImplements(car,CarInterface);
            //return car;
        },
    };
    
    var CarInterface = new Interface("CarInterface",["start","run"]);
    
    function BaseCar(){}
    BaseCar.prototype={
        constructor:BaseCar,
        start:function(){},
        run:function(){}
    };
    
    function Benz(){}
    extend(Benz,BaseCar);
    
    function Bmw(){}
    extend(Bmw,BaseCar);
    
    function Audi(){}
    extend(Audi,BaseCar);
    
    var shop=new CarShop();    
    var car=shop.sellCar("Benz");
    car.start();
    car.run();
    
    //注:在CarShop的sellCar方法中,既有卖车的逻辑,又有生产车的逻辑(new Benz() new Bmw()...)
    //生产车的逻辑应该交给工厂来做
    //生产一台车,单体模式
    var CarFactory={
        createCar:function(){
            var car;
            switch(type){
                case "Benz":
                    car=new Benz();
                    break;
                case "Bmw":
                    car=new Bmw();
                    break;
                case "Audi":
                    car=new Audi();
                    break;
                default:
                    "没有合适的车";
            }
            Interface.ensureImplements(car,CarInterface);
            return car;
        }
    };
==================复杂工厂(真正的工厂)================
    //买什么车去什么商店->商店->卖车->生产车->工厂
    //需要一个商店抽象类,将CarShop作为抽象类
    function CarShop(){}
    CarShop.prototype={
        constructor:CarShop,
        sellCar:function(type){
            //var car=CarFactory.createCar(type);
            //return car;
            this.abstractSellCar(type);
        },
        abstractSellCar:function(){
            throw new Error("抽象类不可以直接调用");
        }
    };
    
    function BenzCarShop(){}
    extend(BenzCarShop,CarShop);
    BenzCarShop.prototype={
        constructor:BenzCarShop,
        sellCar:function(type){
            var car;
            var types=["Benz"];
            for(var t in types){
                if(types[t]===type){
                    car=CarFactory.createCar(type);
                }else{
                    alert("没有对应的车型号");
                }
            }
            return car;
            //var car=CarFactory.createCar(type);
            //return car;
        }
    };
    
    function BmwCarShop(){}
    extend(BmwCarShop,CarShop);
    BmwCarShop.prototype={
        constructor:BmwCarShop,
        sellCar:function(type){
            var car;
            var types=["Bmw"];
            for(var t in types){
                if(types[t]===type){
                    car=CarFactory.createCar(type);
                }else{
                    alert("没有对应的车型号");
                }
            }
            return car;
            //var car=CarFactory.createCar(type);
            //return car;
        }
    };
    
    var CarInterface = new Interface("CarInterface",["start","run"]);
    
    function BaseCar(){}
    BaseCar.prototype={
        constructor:BaseCar,
        start:function(){},
        run:function(){}
    };
    
    function Benz(){}
    extend(Benz,BaseCar);
    
    function Bmw(){}
    extend(Bmw,BaseCar);
    
    function Audi(){}
    extend(Audi,BaseCar);
    
    var CarFactory={
        createCar:function(){
            //利用eval动态创建传入类型的实例对象
            var car=eval("new "+type+"()");
            Interface.ensureImplements(car,CarInterface);
            return car;
        }
    };
    
    var shop1=new BenzCarShop();
    var car1=shop1.sellCar();
    car1.run();

5、桥接模式

桥接模式
    事件绑定
    window.onload=function(){
        var oInput=document.getElementById("ipt");
        oInput.addEventListener("click",sendReq,false);
        
        function sendReq(){
            $.post("URL",{msg:"abc"},function(result){
                
            });
        }
    };
    特权函数 使内部和外部解耦
    function Public(){
        var name="张三";
        this.getName=function(){
            return name;
        };
    }
    
    var p1=new Public();
    alert(p1.getName());
    ===============
    function Public(){
        var privateMethod=function(){
            alert("复杂操作");
        };
        
        this.bridgeMethod=function(){
            return privateMethod();
        };
    }
    var p1=new Public();
    p1.bridgeMethod();
    ==============
    用桥把多个单体组织在一起
    使每个单元都能独立化,可以实现自己的变化
    function Class1(a,b,c){
        this.a=a;
        this.b=b;
        this.c=c;
    }
    function Class2(d,e){
        this.d=d;
        this.e=e;
    }
    function BridgeClass(a,b,c,d,e){
        this.class1=new Class1(a,b,c);
        this.class2=new Class2(d,e);
    }

6、组合模式

  专门为Web上的动态用户界面而量身定制的
  这种模式可以用一条命令在多个对象上激发复杂的或递归的行为
  好处:用同样的方法处理对象的集合与其中的特定子对象
  还可以用来把一批子对象组织成树状结构,并且使整棵树都可以被遍历

function Org(name){
        this.name=name;
        this.depts=[];
    }
    Org.prototype={
        constructor:Org,
        addDepts:function(child){
            this.depts.push(child);
            return this;
        },
        getDepts:function(){
            return this.depts;
        }
    };
    
    function Dept(name){
        this.name=name;
        this.persons=[];
    }
    Dept.prototype={
        constructor:Dept,
        addPersons:function(child){
            this.persons.push(child);
            return this;
        },
        getPersons:function(){
            return this.persons;
        }
    };

    function Person(name){
        this.name=name;
    }

    Person.prototype={
        constructor:Person,
        hardworking:function(){
            alert("working");
        },
        sleeping:function(){
            alert("sleeping");
        }
    };

    var p1=new Person("张1");
    var p2=new Person("张2");
    var p3=new Person("张3");
    var p4=new Person("张4");
    var p5=new Person("张5");
    var p6=new Person("张6");

    var dept1=new Dept("开发部");
    dept1.addPersons(p1).addPersons(p2).addPersons(p3);
    var dept2=new Dept("销售部");
    dept2.addPersons(p4).addPersons(p5).addPersons(p6);

    var org=new Org("bjsxt");
    org.addDepts(dept1).addDepts(dept2);

    //需求:具体让某个人工作
    for(var i=0,depts=org.getDepts();i<depts.length;i++){
        var dept=depts[i];
        for(var j=0;j<dept.getPersons().length;j++){
            if(dept.getPersons()[j].name==="张3"){
                dept.getPersons()[j].hardworking();
            }
        }
    }
    //当需求更改为开发部下又分为开发部1 开发部2 开发部3
    //再让某个子开发部的某个人去工作,那么for循环就会再嵌套一层,if判断也更加复杂
    //业务逻辑的更改造成了代码的大幅度变化
    //此时我们可以让组合模式来帮我们

    //组合模式应用的场景和特点
    //场景:
    //1、存在一批组织成某种层次体系的对象
    //2、希望对这批对象或其中一部分对象实施一个操作

    //特点:
    //组合模式中只有两种类型对象:组合对象、叶子对象
    //这两种类型都实现同一批接口
    //一般我们会在组合对象中调用其方法并隐式调用下级方法,一般会采用递归的形式实现
    
    //组合对象
    function Composite(name){
        this.name=name;
        this.type="Composite";//说明对象的类型
        this.children=[];
    }
    Composite.prototype={
        constructor:Composite,
        addChild:function(child){
            this.children.push(child);
            return this;
        },
        getChild:function(name){
            var elements=[];
            var pushLeaf=function(item){
                if(item.type === "Composite"){
                    item.children.each(arguments.callee);
                }else if(item.type === "Leaf"){
                    elements.push(item);
                }else{
                    throw new Error("类型错误");
                }
            };
            if(name && this.name !== name){//根据name让指定name下的Leaf对象执行操作
                this.children.each(function(item){
                    if(item.name === name && item.type === "Composite"){
                        item.children.each(pushLeaf);
                    }else if(item.name !=== name && item.type === "Composite"){
                        item.children.each(arguments.callee);
                    }else if(item.name === name && item.type === "Leaf"){
                        elements.push(item);
                    }
                });
            }else{//让所有的Leaf结点执行操作
                //this.children得到的时开发部和销售部
                this.children.each(pushLeaf);
            }
            return elements;
        },
        hardworking:function(name){
            //得到所有的Leaf类型的对象
            var leafObject=this.getChild(name);
            for(var i=0;i<leafObject.length;i++){
                leafObject[i].hardworking();
            }
        },
        sleeping:function(name){            
            var leafObject=this.getChild(name);
            for(var i=0;i<leafObject.length;i++){
                leafObject[i].sleeping();
            }
        }
    };
    //叶子对象
    function Leaf(name){
        this.name=name;
        this.type="leaf";
    }
    Leaf.prototype={
        constructor:Leaf,
        addChild:function(child){
            throw new Error("叶子结点不能添加子对象");
        },
        getChild:function(name){
            if(this.name==name){
                return this;
            }
            return null;
        },
        hardworking:function(){
            alert(this.name+" working");
        },
        sleeping:function(){
            alert(this.name+" sleeping");
        }
    };

    var CompositeInterface=new Interface("CompositeInterface",["getChild","addChild"]);
    var LeafInterface=new Interface("LeafInterface",["hardworking","sleeping"]);
    
    var p1=new Leaf("张1");
    var p2=new Leaf("张2");
    var p3=new Leaf("张3");
    var p4=new Leaf("张4");
    var p5=new Leaf("张5");
    var p6=new Leaf("张6");

    var dept1=new Composite("开发部");
    dept1.addChild(p1).addChild(p2).addChild(p3);
    var dept2=new Composite("销售部");
    dept2.addChild(p4).addChild(p5).addChild(p6);

    var org=new Composite("bjsxt");
    org.addChild(dept1).addChild(dept2);
    
    org.hardworking("开发部");
    //如果不传参数,就让所有结点调用hardworking方法
    org.hardworking();

7、门面模式

    //门面模式的两个作用:简化类的接口,消除类和使用它的客户代码之间的耦合
    //是最常用的设计模式
    //最经典的就是事件
    
    //做一件事情 必须调用2个函数 分别是a b
    //其实就是不要把所有的逻辑都写在一个函数里面,要分开写
    function a(x){}
    function b(y){}
    function ab(x,y){
        a(x);
        b(y);
    }

8、适配器模式

   //现有的接口和不兼容的类之间进行适配。使用这种模式的对象又叫包装器,因为他们是在用一个新的接口包装另一个对象。借助适配器可以处理一些与API不匹配、不能一同使用的情况 
    var obj={
        str1:"111",
        str1:"222",
        str1:"333"
    };
    
    function adapter(obj){
        interfaceMethod(obj.str1,obj.str2,obj.str3);
    }
    
    function interfaceMethod(x,y,z){
        
    }
    ===================
    //假设要兼容YUI和prototype两个库
    function $(){
        var elements=[];
        for(var i=0;i<arguments.length;i++){
            var element=arguments[i];
            if(typeof element === "string"){
                element=document.getElementById(element);
            }
            if(arguments.length === 1){
                return element;
            }
            elements.push(element);
        }
        return elements;
    }
    var yahoo={};
    yahoo.get=function(el){
        if(typeof el==="string"){
            return document.getElementById(el);
        }
        if(el instanceof Array){
            var elements=[];
            for(var i=;i<el.length;i++){
                elements.push(yahoo.get(el[i]));
            }
            return elements;
        }
        if(el){
            return el;
        }
        return null;
    };
    yahoo.get=yuiToPrototypeAdapter;
    function yuiToPrototypeAdapter(){
        if(arguments.length === 1){
            return $.apply(window,e instanceof Array?e:[e]);
        }else{
            return $.apply(window,arguments);//或者用call也行
        }
    }
    window.onload=function(){
        //var domarr=$("inp1","inp2"); prototype风格写法
        //var domarr=yahoo.get(["inp1"]); YUI风格写法
        
        //适配器模式的目的就是要让以下prototype的参数风格传入yahoo框架也可以使用
        yahoo.get("inp1","inp2");
    };

9、装饰者模式

    //为对象添加新特性的技术
    //实现同样的接口
    //需要有子类
    var CarInterface=new Interface("CarInterface",["getPrice","assemble"]);
    function Car(car){
        //就是为了让子类继承的 让子类多一个父类的引用
        this.car=car;
        //检查接口
        Interface.ensureImplements(this,CarInterface);
    }
    Car.prototype={
        constructor:Car,
        getPrice:function(){
            return 200000;
        },
        assemble:function(){
            alert("组装汽车");
        }
    };
    //如果新的需求需要创建子类,而子类有可能会影响到父类的某些属性
    //这时就要用装饰者模式
    //用来把原始对象包装在具有同样接口的另一个对象中
    function LightDecorator(car){//参数car代表原始对象
        //LightDecorator.superClass是父类的原型对象
        Car.call(this,car);
    }
    extend(LightDecorator,Car);
    
    LightDecorator.prototype={
        constructor:LightDecorator,
        getPrice:function(){
            return this.car.getPrice()+10000;//在子类上修改,没有影响到父类
        },
        assemble:function(){
            alert("组装汽车");
        }        
    };
    
    function IceBoxDecorator(car){
        LightDecorator.call(this,car);
    }
    extend(IceBoxDecorator,Car);
    IceBoxDecorator.prototype={
        constructor:IceBoxDecorator,
        getPrice:function(){
            return this.car.getPrice()+20000;//在子类上修改,没有影响到父类
        },
        assemble:function(){
            alert("组装汽车");
        }    
    };
    
    var car=new Car();
    alert(car.getPrice());
    
    car=new LightDecorator(car);
    alert(car.getPrice());
    
    car=new IceBoxDecorator(car);
    alert(car.getPrice());
    =================================================
    //装饰者模式不仅可以用在类上,还可以用在函数上
    function getDate(){
        return new Date().toString();
    }
    //包装函数
    function upperCaseDecorator(fn){
        return function(){
            return fn.apply(this,arguments).toUpperCase();
        };
    }

10、享元模式

    //出厂商 出厂日期 拥有者 车牌号 登记日期
    function Car(make,model,year,owner,tag,renewDate){
        this.make=make;
        this.model=model;
        this.year=year;
        this.owner=owner;
        this.tag=tag;
        this.renewDate=renewDate;
    }
    Car.prototype={
        constructor:Car,
        getMake:function(){
            return this.make;
        },
        getModel:function(){
            return this.model;
        },
        getYear:function(){
            return this.year;
        },
        renewRegistration:function(newRenewDate){
            this.renewDate=newRenewDate;
        }
    };
    var arr=[];
    var start=new Date().getTime();
    for(var i=0;i<5000000;i++){
        arr.push(new Car("aaa","bbb","2012","ccc","112233","2013"));
    }
    var end=new Date().getTime();
    alert(end-start);//700多毫秒
    //占用内存大约 570M左右
    
    //我们接下来用享元模式优化它
    //内在数据:可以共享的属性
    //外在数据:不能共享的属性
    //享元模式要把内在数据抽出
    
    
    function Car(make,model,year){
        this.make=make;
        this.model=model;
        this.year=year;
    }
    Car.prototype={
        constructor:Car,
        getMake:function(){
            return this.make;
        },
        getModel:function(){
            return this.model;
        },
        getYear:function(){
            return this.year;
        }
    };
    
    //工厂模式 利用闭包工厂把静态的东西初始化出来
    var CarFactory=(function(){
        //已经生产好的car
        var createdCars={};
        return {
            createCar:function(make,model,year){
                //如果createdCars对象里已经存在当前的make model year 
                if(createdCars[make+model+year]){
                    return createdCars[make+model+year];
                }else{
                    var car=new Car(make,model,year);
                    createCars[make+model+year]=car;
                    return car;
                }
            }
        };
    })();
    //用单体模式把外在的数据和内在的数据结合在一起
    var CarRecordManager=(function(){
        //把登记号的汽车防盗这个对象里
        var carRecordDataBase={};
        return {
            addCarRecord:function(make,model,year,owner,tag,renewDate){
                var car=CarFactory.createCar(make,model,year);
                carRecordDataBase[tag]={
                    owner:owner,
                    renewDate:renewDate,
                    car:car
                };
            },
            renewRegistration:function(tag,newRenewDate){
                carRecordDataBase[tag].renewDate=newRenewDate;
            }
        };
    })();
    var arr=[];
    var start=new Date().getTime();
    for(var i=0;i<5000000;i++){
        arr.push(CarRecordManager.addCarRecord("aaa","bbb","2012","ccc","112233","2013"));
    }
    var end=new Date().getTime();
    alert(end-start);//3000-5000多毫秒
    //内存大约占用290M左右
    
    //时间和空间不可兼得
    //模拟web日历 并利用享元模式优化
    var CalendarInterface=new Interface("CalendarInterface",["display"]);
    function CalendarYear(year,parent){
        this.year=year;
        this.element=document.createElement("div");
        this.element.style.display="none";
        parent.appendChild(this.element);
        
        this.months=[];
        this.numDays=[31,isLeapYear(this.year)?29:28,31,30,31,30,31,31,30,31,30,31];
        for(var i=0;i<12;i++){
            this.months[i]=new CalendarMonth(i,this.numDays[i],this.element);
        }
    }
    CalendarYear.prototype={
        constructor:CalendarYear,
        display:function(){
            for(var i=0;i<this.months.length;i++){
                this.months[i].display();
            }
            this.element.style.display="block";
        }
    };
    function CalendarMonth(monthNum,numDays,parent){
        this.monthNum=monthNum;
        this.element=document.createElement("div");
        this.element.style.display="none";
        parent.appendChild(this.element);
        
        this.days=[];
        
        for(var i=0;i<numDays;i++){
            this.days[i]=new CalendarDay(i+1,this.element);
        }
    }
    CalendarMonth.prototype={
        constructor:CalendarMonth,
        display:function(){
            for(var i=0;i<this.days.length;i++){
                this.days[i].display();
            }
            this.element.style.display="block";
        }
    };
    function CalendarDay(date,parent){
        this.date=date;
        this.element=document.createElement("div");
        this.element.style.display="none";
        parent.appendChild(this.element);
    }
    CalendarDay.prototype={
        constructor:CalendarDay,
        display:function(){
            this.element.style.display="block";
            this.element.innerHTML=this.date;
        }
    };

    function isLeapYear(y){
        return (y>0) && !(y%4) && ((y%100) || !(y%400));
    }
    
    window.onload=function(){
        var mydiv=document.getElementById("mydiv");
        var myyear=new CalendarYear(2014,mydiv);
        myyear.display();
        
        //一年都要new出来365个对象,年多了性能就很差了
    };
    
    <div id="mydiv"></div>

    //享元模式优化上面的日历 主要优化天对象
    function CalendarMonth(monthNum,numDays,parent){
        this.monthNum=monthNum;
        this.element=document.createElement("div");
        this.element.style.display="none";
        parent.appendChild(this.element);
        
        this.days=[];
        
        for(var i=0;i<numDays;i++){
            //只用这一个实例
            this.days[i]=calendarDaySingleInstance;
        }
    }
    CalendarMonth.prototype={
        constructor:CalendarMonth,
        display:function(){
            for(var i=0;i<this.days.length;i++){
                this.days[i].display(i+1,this.element);
            }
            this.element.style.display="block";
        }
    };
    
    function CalendarDay(){}
    CalendarDay.prototype={
        constructor:CalendarDay,
        display:function(date,parent){
            var element=document.createElement("div");
            parent.appendChild(element);
            element.style.display="block";
            element.innerHTML=date;
        }
    };
    var calendarDaySingleInstance=new CalendarDay();
原文地址:https://www.cnblogs.com/zhaohuiziwo901/p/5269338.html