Anita-Mul / Javascript-

【Javascript设计模式与开发实战源码】

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

单例模式

定义
  • 保证一个类仅有一个实例,并提供一个访问它的全局访问点
  • 例: 线程池、全局缓存、浏览器中的window对象
写法
  • 通用写法
    var Example = (function() {
        var instance;
    
        return function() {
            if(!instance) {
                ...
            }
    
            return instance;
        }
    })();
    
    var a = new Example();
    var b = new Example();
    
    alert(a === b);
  • 对象字面量
    var namespace1 = {
        a: function() {
            alert(1);
        },
        b: function() {
            alert(2);
        },
    };
  • 使用闭包封装私有变量
    var user = (function() {
        var __name = 'jack',
            __age = 19;
        
        return {
            getUserInfo: function() {
                return __name + '_' + __age;
            }
        }
    })();

策略模式

  • 定义策略类
    var strategies = {
        "S": function(salary) {
            return salary * 4;
        },
        "A": function(salary) {
            return salary * 3;
        },
        "B": function(salary) {
            return salary * 2;
        }
    };
  • 定义调用函数
    var calculateBonus = function(level, salary) {
        return strategies[level](salary);
    };
  • 当一件事情的发生对应多种策略,可以在调用函数的方式上做文章【4 - 表单校验】

代理模式

  • 代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问
  • 意思就是访问硬件或者网络啥的需要时间,代理在这个时间里干点啥,体验好
  • 事情原本的做法
    var myImage = (function() {
        var imgNode = document.createElement('img');
        document.body.appendChild(imgNode);
    
        return {
            setSrc: function(src) {
                imgNode.src = src;
            }
        };
    })();
  • 控制访问 function
    var proxyImage = (function() {
        var img = new Image;
        img.onload = function() {
            // myImage.setSrc(this.src);
            // 变得太快,看不出效果,所以加了定时器
            setTimeout(() => {
                myImage.setSrc(img.src);
            }, 1000);
        };
    
        return {
            setSrc: function(src) {
                // loading   
                myImage.setSrc('https://pic3.zhimg.com/v2-d0e1883a8b5126baeaf677cfcd3a302e_b.webp');
                // real
                img.src = src;
            },  
        };
    })();
    
    proxyImage.setSrc("https://pic2.zhimg.com/v2-227d2013bf43c562113f2dc6d918f7d5_b.jpg");

命令模式

  • 命令集合
    var SubMenu = {
        add: function() {
            console.log('增加子菜单');
        },
        del: function() {
            console.log('删除子菜单');
        }
    };
  • 添加命令
    var AddSubMenuCommand = function(receiver) {
        // return function() {
        //     receiver.add();
        // };
        return {
            execute: function() {
                receiver.add();
            }
        };
    };
    
    // 或者,也可以直接写成这样
    var openQQCommand = {
        execute: function() {
            console.log('登录QQ');
        }
    };
  • 执行命令
    var setCommand = function(button, command) {
        // button.onclick = function() {
        //     func();
        // }
        button.onclick = function() {
            command.execute();
        };
    };

组合命令

  • 父类
    var Folder = function(name) {
        this.name = name;
        this.parent = null;  // 头节点的父节点为空
        this.files = [];
    };
    
    Folder.prototype.add = function(file) {
        file.parent = this;      // 设置父对象
        this.files.push(file);
    };
    
    Folder.prototype.scan = function() {
        for(var i = 0, file, files = this.files; file = files[i++]; ) {
            file.scan();
        };
    };
  • 子类
    var File = function(name) {
        this.name = name;
    };
    
    File.prototype.add = function() {
        throw new Error('文件下面不能再添加文件');
    };
    
    File.prototype.scan = function() {
        console.log('开始扫描文件:' + this.name);
    };
    
    File.prototype.remove = function() {
        if(!this.parent) {
            return;
        }
    
        for(var files = this.parent.files, l = files.length - 1; l >= 0; l--) {
            var file = files[l];
            if(file === this) {
                files.splice(l, 1);
            }
        }
    };

模板方法模式

  • 父类
    var Beverage = function() {};
    
    Beverage.prototype.boilWater = function() {
        console.log('把水煮沸');
    };
    
    Beverage.prototype.brew = function() {
        throw new Error('子类必须重写brew方法');
    };
    
    Beverage.prototype.init = function() {
        this.boilWater();
        this.brew();
    };
  • 子类
    var Coffee = function() {};
    
    Coffee.prototype = new Beverage();
    Coffee.prototype.brew = function() {
        console.log('用沸水冲泡咖啡');
    }
  • 不需要继承的方法
    var Beverage = function(param) {
        var boilWater = function() {
            console.log('把水煮沸');
        };
    
        var brew = param.brew || function() {
            throw new Error('必须传递brew方法');
        };
    
        var F = function() {};
    
        F.prototype.init = function() {
            boilWater();
            brew();
        };
    
        return F;
    };
    
    var Coffee = Beverage({
        brew: function() {
            console.log('用沸水冲泡咖啡');
        }
    });

享元模式

  • 传入创建对象的方法,对象池存储对象
    var objectPoolFactory = function(createObjFn) {
            var objectPool = [];
            return {
                create: function() {
                    var obj = objectPool.length === 0 ? createObjFn.apply(this, arguments) : objectPool.shift();
                    return obj;
                },
                recover: function(obj) {
                    objectPool.push(obj);
                }
            }
        };
  • 传入创建对象的方法
    var iframeFactory = objectPoolFactory(function() {
        var iframe = document.createElement('iframe');
        document.body.appendChild(iframe);
    
        iframe.onload = function() {
            iframe.onload = null;
            iframeFactory.recover(iframe);
        };
    
        return iframe;
    });

职责链模式

  • 链的数据结构
    var Chain = function(fn) {
        this.fn = fn;
        this.successor = null;
    };
    
    // 指定在链中的下一个节点
    Chain.prototype.setNextSuccessor = function(successor) {
        return this.successor = successor;
    };
    
    // 既可以让函数返回 'nextSuccessor' 来调用下一个,也可以在函数中调用 next() 来调用下一个
    Chain.prototype.passRequest = function() {
        // 在一条链上传递的是相同的参数 arguments
        var ret = this.fn.apply(this, arguments);
    
        if(ret === 'nextSuccessor') {
            return this.successor && this.successor.passRequest.apply(this.successor, arguments);
        }
    
        return ret; 
    };
    
    Chain.prototype.next = function() {
        return this.successor && this.successor.passRequest.apply(this.successor, arguments);
    };
  • 在 function 上绑定 after
    Function.prototype.after = function(fn) {
        var self = this;
        return function() {
            var ret = self.apply(this,arguments);
            if(ret === 'nextSuccessor') {
                return fn.apply(this, arguments);
            }
            return ret;
        }
    };
    
    var order = order500.after(order200).after(orderNormal);

装饰者模式

  • 主要功能
    var plane = {
        fire: function(){
            console.log( '发射普通子弹' );
        }
    }
    // ——————————————————————————————————
    var Plane = function() {};
    Plane.prototype.fire = function() {
        console.log('发射普通子弹');
    };
  • 装饰方法
    var missileDecorator = function(){
        console.log( '发射导弹' );
    }
    // ——————————————————————————————————
    var MissileDecorator = function(plane) {
        this.plane = plane;
    };
    MissileDecorator.prototype.fire = function() {
        this.plane.fire();
        console.log('发射导弹');
    };
  • 装饰
    var fire1 = plane.fire;
    
    plane.fire = function(){
        fire1();
        missileDecorator();
    }
  • AOP 装饰函数
    Function.prototype.before = function( beforefn ){
        var __self = this;                         
        return function(){                         
            beforefn.apply( this, arguments );       
                                                    
            return __self.apply( this, arguments );  
                                                    
        }
    }
    
    Function.prototype.after = function( afterfn ){
        var __self = this;
        return function(){
            var ret = __self.apply( this, arguments );
            afterfn.apply( this, arguments );
            return ret;
        }
    };

About

【Javascript设计模式与开发实战源码】


Languages

Language:HTML 84.6%Language:JavaScript 15.4%