设计者模式 数据塌陷

这篇博客探讨了JavaScript中的单例模式,确保类只有一个实例。接着介绍了组合模式,展示了如何批量启动多个效果,如轮播图、tab切换和放大镜。然后讲解了观察者模式,模拟了事件监听和触发的实现。最后提到了数据处理中的问题,如数据塌陷,并提供了解决方案以及数据劫持的概念,展示了如何实现数据双向绑定。
摘要由CSDN通过智能技术生成

单例模式

正常情况,一个类创建出来的每个对象都是不一样的。

class Carousel{ } var a = new Carousel(); var b = new Carousel(); console.log(a === b); // false

单例模式就是让这两个对象是一样的,也就是说,一个类永远只有一个实例对象

var single = (function(){
    class Carousel{
       
    }
    var res = undefined;
    return function(){
        if(!res){
           res = new Carousel();
        }
        return res;
    }
})();
var s1 = single();
var s2 = single();
console.log(s1 === s2); // true

组合模式

<script>
// 组合模式:批量启动的启动器
// 轮播图、tab切换、放大镜 - init - 启动方法
class Carousel{
    init(){
        console.log("轮播图启动了");
    }
}
class Tab{
    init(){
        console.log("tab切换启动了");
    }
}
class Enlarge{
    init(){
        console.log("放大镜启动了");
    }
}
// 一种固定的模式,能将这3个效果一起启动起来
class Startor{
    // 定义constructor,定义存放所有效果对象的容器
    constructor(){
        this.container = [];
    }
    // 添加要启动的那些效果对象
    add(...arr){ // 将所有实参都收集为一个数组
        this.container = this.container.concat(arr)
    }
    // 将添加好的效果对象,集体调用他们的init启动
    init(){
        // 遍历上面的arr,将arr中每个对象都调用init就好了
        this.container.forEach(item=>item.init())
    }
}
var s = new Startor()
// 添加了个效果
s.add(new Carousel,new Tab,new Enlarge)
s.add(new Carousel,new Tab)
// 全部启动
s.init()
</script>

设计者模式

<script>
// var obj = {}
// console.log(obj);
// // obj.addEventListener('click',fn)
// document.addEventListener('abc',fn)
// function fn(){
//     console.log("点击了");
// }
// 观察者模式:
/*
1.给任意对象都可以绑定事件
2.可以绑定任意类型的事件
*/
/*
模拟addEventListener
    同类型绑定多次
    手动触发
    解绑事件
    触发时能给事件函数传递参数
*/
// 定义类
class Observer{
    // 定义存储事件的容器
    constructor(){
        this.container = {}
    }
    // 绑定事件的方法
    addEventListener(type, handler){
        // 绑定其实就是将事件类型和对应的函数存起来
        // console.log(type, handler);
        // this.container[type] = [handler]
        // 如果容器中,没有这个类型的事件 - 添加类型 - 值是 []
        if(!this.container[type]){
            this.container[type] = [];
        }
        // 给数组中添加一个函数
        this.container[type].push(handler)
    }
    // 触发事件的方法
    dispatchEvent(type,...brr){
        // 通过事件类型type,到容器中找到对应的数组,将数组中的所有函数调用
        var arr = this.container[type]
        // 遍历
        if(!arr){
            throw new Error("事件"+type+"没有绑定过!")
        }
        // 制造一个事件对象
        var e = {
            type,
            clientX:0,
            clientY:0,
            button:0,
            data:brr
        }
        arr.forEach(item=>item(e))
    }
    // 解绑
    removeEventListener(type, handler){
        // 判断是否绑定过这个事件
        if(!this.container[type]){
            throw new Error("事件"+type+"没有绑定过")
        }
        // 将handler从容器中删除就好了
        // 找handler在数组中的下标
        var index = this.container[type].findIndex(item=>item===handler)
        // 判断index是否找到
        if(index<0){
            throw new Error("事件函数不存在")
        }
        this.container[type].splice(index, 1)
        // 如果删的数组中没有函数了 - 空数组了 - 就删除键值对
        if(!this.container[type].length){
            delete this.container[type]
        }
    }
    // 清除事件对应的所有函数
    clear(type){
        if(!this.container[type]){
            throw new Error("事件"+type+"没有绑定过")
        }
        delete this.container[type]
    }
}
var obj = new Observer()
obj.addEventListener('aa',a1)
function a1(){
    console.log("这是aa事件的a1函数");
}
obj.addEventListener('aa',a2)
function a2(){
    console.log("这是aa事件的a2函数");
}
obj.addEventListener('bb',b1)
function b1(e){
    console.log("这是bb事件的b1函数");
    console.log(e);
}
// 解绑
obj.removeEventListener('aa',a1)
obj.removeEventListener('aa',a2)
// obj.removeEventListener('aa',a1)
// obj.clear('aa')
// obj.removeEventListener('cc')
// 触发
// obj.dispatchEvent('aa')
// obj.dispatchEvent('bb',10,20,30)
// obj.dispatchEvent('cc')
console.log(obj);
</script>

数据塌陷

var arr = [1,2,3,4,5]; for(var i=0;i<arr.length;i++){ arr.splice(i,1); } console.log(arr); // [2,4]

解决办法:

1、倒着删除

for(var i=arr.length-1;i>=0;i--){ arr.splice(i,1); }

2、不让变量递增

for(var i=0;i<arr.length;i++){ arr.splice(i,1); i--; }

3、每次都删除最后一个代码

var length = arr.length; for(var i=0;i<length;i++){ arr.splice(0,1); }

数据劫持

<body>
<input type="text" name="keywords" value="12">
</body>
<script>
var obj = {
    age:12
}
/******* 数据双向绑定:  MVVM  *******/
// 当文本框中内容发生改变的时候,希望obj.age也跟着发生改变 - 值一样
// 当对象中的age发生改变的时候,让文本框中的值也跟着发生改变
var keywords = document.querySelector('[name="keywords"]');
keywords.oninput = function(){
    obj.age = this.value
}
console.dir(Object);
// 监听obj的age属性被访问的时候
Object.defineProperty(obj, 'age', {
    get(){
        // console.log(111);
        // 访问obj的age属性,就会先调用get方法,访问到的值,是这个get方法返回的值
        return keywords.value
    },
    set(val){
        // 当修改obj的age属性的值的时候,就会调用set方法 - 即将要改变的值,会被set方法形参接收到
        // console.log(val);
        keywords.value = val
    }
})
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值