美文网首页
成长(11/2000)——面试题合集8

成长(11/2000)——面试题合集8

作者: Kiki_Q | 来源:发表于2021-06-15 21:03 被阅读0次

    js的设计模式

    单例模式

    • 定义:只有一个实例,可以全局访问
    • 主要解决: 一个全局使用的类,频繁的创建和销毁
    • 何时使用: 当你想控制实例的数目,节省系统化资源的时候
    • 如何实现:判断系统是否已经有这个单利,如果有则返回,没有则创建
    • 单利模式优点:内存中只要一个实例,减少内存的开销,尤其是频繁的创建和销毁实例(比如说首页页面的缓存)
    • 使用场景:1.全局的缓存 2.弹窗
    //前景
    class Person {
        constructor(name, sex) {
            this.name = name;
            this.sex = sex;
            //实际开发中,更多的是做初始化的操作
        }
        say() {
            console.log('web');
        }
    }
    
    let person1 = new Person('阿羡','man');
    console.log(person1.name);
    person1.say();
    
    console.log(person1.say === Person.prototype.say);
    
    //es6实现单例
    class demo {
        constructor(name, creator, products){
            this.name = name;
            this.creator = creator;
            this.products = products;
        }
        static getInstance(name, creator, products) {
            if(!this.instance){
                this.instance = new demo(name, creator, products);
            }
            return this.instance;
        }
    }
    
    let demo1 = demo.getInstance(1,2,3);
    let demo2 = demo.getInstance(4,5,6);
    
    console.log(demo1 === demo2); //true
    

    策略模式

    • 定义一系列的算法,把它们封装起来,并且他们之间可以相互替换
    • 核心:将算法的使用和算法的实现分离开来

    实战演练

    • 绩效为S的人年终奖有4倍工资,为A的有3倍...
    1.传统写法缺点:缺乏弹性
    let calculate = function(level,salary){
        if(level == "S"){
            return salary * 4
        }
        if(level == "A"){
            return salary * 3
        }
    }
    
    2.算法的使用和实现分离
    
    
    let pS = function(){};
    pS.prototype.calculate = function (salary) {
        return salary * 4
    }
    let pA = function(){};
    pA.prototype.calculate = function (salary) {
        return salary * 3
    }
    let Bouns = function() {
        this.salary = null;
        this.strategy = null;
    }
    Bouns.prototype.setSalary = function (salary) {
        this.salary = salary;
    }
    Bouns.prototype.setStrategy = function (salary) {
        this.strategy = strategy;
    }
    Bouns.prototype.getBouns = function () {
        return this.strategy.calculate(this.salary)
    }
    
    let bouns = new Bouns();
    bouns.setSalary(10000);
    bouns.setStrategy(new pS());
    console.log(bouns.getBouns());
    
    //函数也是对象
    let strategies = {
        "S": function (){
            return salary * 4;
        },
        "A": function (){
            return salary * 3;
        }
    }
    let getBouns = function (level, salary){
        return strategies[level](salary)
    }
    
    • 运用策略模式封装validator.add(value,'isNonempty','用户名不能为空')等规则的表单校验
    const { ValidationError } = require("schema-utils")
    
    let strategies = {
        isNonEmpty: function (value,errorMsg){
            if(value == '') {
                return errorMsg
            }
        },
        minLength: function (value, length, errorMsg) {
            if(value.length < 6) {
                return errorMsg
            }
        },//minLength:6
        isMobile: function (value, errorMsg) {
            if(!/^1[3|5|8][0-9]{9}$/.test(value)) {
                return errorMsg
            }
        }
    }
    
    let validateFun = function () {
        let validate = new Validator();
        validate.add(registerForm.userName,'isNonEmpty','用户名不能为空');
    
        //开启验证
        let errorMsg = Validator.start();
        return errorMsg;
    
    }
    
    let Validator = function(){
        this.cache = [];
    }
    
    Validator.prototype.add = function (dom, rule,errorMsg) {
        let ary = rule.split(":");
        this.cache.push(function(){
            let strategy = ary.shift();//用户选择的验证规则
            ary.unshift(dom.value);
            ary.push(errorMsg);
            return strategies[strategy].apply(dom, ary)
            //return strategies[strategy](...ary)
        })
    }
    
    Validator.prototype.start = function() {
        for (let index = 0, vaFunc;vaFunc = this.cache[index++]; ) {
                let msg = vaFunc();
                if (msg) {
                    return msg
                }        
        }
    }
    
    registerForm.onsubmit = function(){
        let errorMsg = validateFun()
        if(errorMsg){
            alert(errorMsg)
            return false
        }
    }
    

    发布者订阅者模式

    • 就是对某个对象进行订阅,如果该对象发生变化,就会通知到订阅者做出相应的改变

    如何实现

    • 首先想好谁是发布者
    • 然后给发布者添加一个缓存列表,用于存放回调函数用来通知订阅者
    • 最后就是发布消息,发布者遍历这个缓存列表,依次触发里面存放的订阅者回调函数
    let shopObj = {};//发布者
    shopObj.list = {}; //缓存列表 存放订阅者的函数
    shopObj.listen = function(key,fn){
        if(!this.list[key]){
            this.list[key] = [];
        }
        this.list[key].push(fn)
    }
    
    shopObj.trigger = function(){
        let key = Array.prototype.shift.call(arguments);
        let fns = this.list[key];
        if (!fns || fns.length == 0){
            return
        }
        for (let index = 0,fn; fn = fns[index++]; ) {
            fn.applay(this,arguments);
            // fn(...arguments)
            
        }
    }
    
    shopObj.remove = function(key, fn) {
        let fns = this.list[key];
        if(!fns) {
            return false
        }
        if(!fn){
            fn && (fns.length = 0);
        }else {
            for (let index = fns.length-1; index >= 0; index--) {
                let _fn = fns[index];
                if(_fn == fn){
                    fns.splice(index,1)
                }
                
            }
        }
    }
    
    
    
    shopObj.listen('key',function(){})
    
    //改版
    let Event = (function(){
        let list = {},
        listen,
        trigger,
        remove;
        listen = function(){
            //如上
        };
        trigger = function(){}
        remove = function(){}
    })()
    
    • npm包有 pubsub-js

    使用场景

    • 改进异步操作中的强耦合

    实战演练

    在传统的商城登录模块中

    • 传统登录后相关模块的信息需要更新;但是这种方式如果后期更换了方法名称或者新增了模块,需要修改很多版块,耦合性比较高,维护难
    
    login.succ(function(data) {
        Header.setAvator(data.avatar);
        nav.setAvator(data.avatar);
        message.refresh();
        cart.refresh();
        //等等
        address.refresh()
    })
    
    • 采用发布者订阅者模式后,登录后主动触发相应的模块,各个模块相互独立
    //登录成功触发消息
    $.ajax(`http://xxxx/login`,function(data){
        login.trigger('loginSucc', data);
    })
    
    //各个模块监听登录成功的消息
    let header = (function(){
        login.listen('loginSucc',function(data) {
            header.setAvatar(data.avatar);
        });
        return {
            setAvatar : function(data){
                console.log('设置header模块的头像');
            }
        }
    })()
    

    相关文章

      网友评论

          本文标题:成长(11/2000)——面试题合集8

          本文链接:https://www.haomeiwen.com/subject/jycoeltx.html