JS设计模式

JS设计模式

节流模式

节流模式的核心思想是创建定时器,延迟程序的执行。

委托模式

给事件发生的上一层最近的父元素绑定事件 ,用e.target去寻找事件触发的具体对象 进行实现事件。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件委托</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }
        li {
            width: 100px;
            height: 30px;
            line-height: 30px;
            background-color: lightblue;
            margin-bottom: 5px;
        }
        span {
            float: right;
            width: 20px;
            height: 20px;
            font-size: 20px;
            cursor: pointer;
        }
        #btn {
            width: 100px;
            height: 30px;
        }
    </style>
</head>
<body>
    <ul id="list">
        <li><span>&times;</span></li>
        <li><span>&times;</span></li>
        <li><span>&times;</span></li>
    </ul>
    <button id="btn">添加li</button>
    <script type="text/javascript">
    // 要求: 点击btn 添加li 点击li 背景颜色改变, 点击span 删除li
    // 获取元素
    var ul = document.getElementById("list");
    var btn = document.getElementById("btn");
    // 添加点击事件
    btn.onclick = function() {
        ul.innerHTML += "<li><span>&times;</span></li>"
    }
    // 委托模式可以解决: 1 预言未来元素 2 防止内存泄漏 3 减少事件数量
    ul.onclick = function(e) {
        // console.log(e.target)
        // 进行判定点击的是哪个元素
        if (e.target.nodeName.toLowerCase() === "span") {
            // 此时e.target是span
            this.removeChild(e.target.parentNode);
        } else if (e.target.tagName.toLowerCase() === "li") {
            // 此时e.target是li
            e.target.style.backgroundColor = "pink"
        }
    }
    </script>
</body>
<html>

工厂模式

工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
工厂函数就是做一个对象创建的封装,并将创建的对象return出去
优点: 能解决多个相似的问题。
缺点: 不能知道对象识别的问题(对象的类型不知道)。
复杂的工厂模式定义是:将其成员对象的实列化推迟到子类中,子类可以重写父类接口方法以便创建的时候指定自己的对象类型。
父类只对创建过程中的一般性问题进行处理,这些处理会被子类继承,子类之间是相互独立的,具体的业务逻辑会放在子类中进行编写。

function Animal(opts){ 
     var obj = new Object(); 
     obj.color = opts.color; 
     obj.name= opts.name; 
     obj.getInfo = function(){ 
          return '名称:'+ onj.name+', 颜色:'+ obj.color; 
      } 
     return obj; 
} 
var cat = Animal({name: '波斯猫', color: '白色'}); 
cat.getInfo();

构造函数模式

function Animal(name, color){ 
    this.name = name;   
   this.color = color;   
   this.getName = function(){ 
      return this.name;
   } 
} 
// 实例一个对象 
var cat = new Animal('猫', '白色'); 
console.log( cat.getName() );

迭代器模式

迭代器模式:在不暴露内部结构的情况下顺序的遍历内部数据
判断target是 数组还是对象
方式1target instanceOf Array(用instanceof)
方式2target.target.constructor
方式3Object.prototype.toString.call(target)

<script>
        function each(target, fn){
            // 判断 target是数组还是对象
            // 方式1  target instanceof Array     用instanceof
            if(target instanceof Array){
                for(var i = 0; i < target.length; i++){
                    fn(target[i], i);
                }
            }else if(target instanceof Object){
                for(var i in target){
                    fn(target[i], i);
                }
            }

            // 方式2  target.constructor
            if(target.constructor == Array){
                for(var i = 0; i < target.length; i++){
                    fn(target[i], i);
                }
            }else if(target.constructor == Object){
                for(var i in target){
                    fn(target[i], i)
                }
            }

            // 方式3  Object.prototype.toString.call(target) (推荐第三种)
            if (Object.prototype.toString.call(target)=== '[object Array]') {
                // 说明是数组
                for (var i = 0; i < target.length; i++) {
                    fn(target[i], i);
                }
            } else if (Object.prototype.toString.call(target)=== '[object Object]') {
                for (var i in target) {
                    fn(target[i], i)
                }
            }

        }
        
        var arr = ["a", "b", "c", 'd', "e", "f", "g"];
        each(arr, function(value, index) {
            console.log(value, index)
        });

        var obj =  {
            name: "xwen",
            age: 3,
            sex: "女"
        };
        each(obj, function(value, index) {
            console.log(value, index)
        });
    </script>

策略模式

将定义的一组算法封装起来,使其相互之间可以替换。
封装的算法具有一定独立性,不会随客户端变化而变化。
策略模式主要是一 种用于处理多种分支判断的模式.

// 以下的都是策略(strategy)
var strategies = {     
    "S": function( salary ){         
        return salary * 4;     
    },     
    "A": function( salary ){         
        return salary * 3;     
    },     
    "B": function( salary ){         
        return salary * 2;     
    }
};  
// 以下就是环境(context)  没有改变,和上面的一样
var Bonus = function(){
    this.salary = null;         // 原始工资  
    this.strategy = null;       // 绩效等级对应的策略对象
};
Bonus.prototype.setSalary = function( salary ) {
    this.salary = salary;        // 设置员工的原始工资
}

Bonus.prototype.setStrategy = function( strategy ) {
    this.strategy = strategy;       
}
Bonus.prototype.getBonus = function() {
    return this.strategy.calculate( this.salary );    
    // 把计算奖金的操作委托给对应的策略对象
}
// 以下是实例
var calculateBonus = function( level, salary ){     
    return strategies[ level ]( salary );
};
console.log(calculateBonus('S', 20000));     // 输出:80000
console.log(calculateBonus('A', 10000));     // 输出:30000

单例模式

利用闭包和立即执行函数来实现
单例模式: 保证一个类只有一个实例,一般先判断实例是否存在,如果存在直接返回,不存在则先创建再返回,这样就可以保证一个类只有一个实例对象。

作用
(1)、保证某个类的对象的唯一性;
(2)、模块间通信;
(3)、防止变量污染
单例模式的核心:确保 一个特定类只有一个实例,并提供这个实例的全局访问

应用场景:

对象往往仅需要一个的时候
(1)windows的任务管理器
(2)多线程的线程池设计
(3)全局缓存
(4)浏览器的window对象
(5)登录页面中的浮窗,无论点击多少次,浮窗仅仅会被创建一次,那么这个button应该使用 单例模式来进行创建。

// 实现单体模式创建div
var createDiv= (function(){
    var div;
    return function(){
       if(!div) {
           div = document.createElement("div");
           div.style.width = '100px';
           div.style.height = '100px';
           div.style.background = '#e4e4e4';
           document.body.appendChild(div);
     }
    return div;
  }
})();
var div1=createDiv();
var div2=createDiv();
console.log(div1===div2); //true

DOM2级观察者模式

观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。

使用场景

1.事件多级触发场景。
2.跨系统的消息交换场景,如消息队列、事件总线的处理机制。
3.观察者模式主要用于在关联行为之间建立一套触发机制的场景。
比如:微信朋友圈动态通知、GPser 生态圈消息通知、邮件通知、广播通知、桌面程序的事件响应等
优点:解除耦合,让耦合的双方都依赖于抽象,从而使得各自的变换都不会影响另一边的变换。
缺点:在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。

<script>
        var Observer = (function () {
            var _O = {
            }
            return {
                on: function (name, fn) {
                    // 先判定对象的该属性是否已经是数组
                    if (_O[name]) {
                        // 如果已经是数组  直接把函数往里添加
                        _O[name].push(fn)
                    } else {
                        // 说明还没有值 设置为数组
                        _O[name] = [fn];
                    }
                },
                trigger: function (name, ...args) {
                    for (var i = 0; i < _O[name].length; i++) {
                        _O[name][i](...args)
                    }
                }
            }
        })();
       


        // 第一个人的代码
        ; (function () {
            // 获取元素
            var num = document.getElementById("num");
            // 使用观察者模式 向消息管道中注册事件
            Observer.on("publish", function () {
                num.innerHTML++;
            });
            Observer.on('remove', function () {
                num.innerHTML--;
            });
        })();


        // 第二个人的代码
        ; (function () {
            // 获取元素
            var list = document.getElementById("list");
            // 第二个人发现 代码不是立刻执行的 所以提前封装好业务逻辑 放入一个函数  
            //等用户点的时候 调用这个函数就好了  第三个人也只需要给这个函数传递参数即可
            Observer.on("publish", function (msg) {
                list.innerHTML += `<li><span>${msg}</span><i>&times;</i></li>`;
            });

            // 委托模式添加点击事件
            list.onclick = function (e) {
                if (e.target.tagName.toLowerCase() === "i") {
                    e.target.parentNode.remove();
                    Observer.trigger("remove");
                }
            }
        })();


        // 第三个人的代码
        ; (function () {
            // 获取元素
            var message = document.getElementById("message");
            var btn = document.getElementById("btn");
            // 添加事件
            btn.onclick = function () {
                // 获取数据
                var value = message.value;
                // 调用其他人提供的函数 并传递参数
                Observer.trigger("publish", value)
            }
        })();
      
        // 注: DOM的事件机制 本质也是用观察者模式实现的
    </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值