当前位置: 首页 > news >正文

前端设计模式

1、模块模式
在立即执行函数表达式中定义的变量和方法,在该函数外部是访问不到的,只能通过该函数提供的接口,"有限制的"进行访问;通过函数的作用域,解决了属性和方法的封装问题。
最常见的立即执行函数写法有以下两种:

(function(){ /* code */ }())
或者
(function(){ /* code */ })()

模块模式代码:

    let Person = (function(){
        var age = "12";
        var name = "jerry";
        function getAge(){
            return age;
        }
        function getName(){
            return name;
        }
        return {
            getAge: getAge,
            getName: getName
        }
    })()
    console.log(age, 'age'); // 报错: Uncaught ReferenceError: age is not defined
    console.log(name, 'name'); // 空字符串,为啥不报错?看底部备注
    console.log(Person.age); // undefined
    console.log(Person.name); // undefined
    // 只能通过Person提供的接口访问相应的变量
    console.log(Person.getName()); // jerry
    console.log(Person.getAge()); // 12

2、构造函数模式

    function Person(name,age){
        this.name = name;
        this.age = age;
    }
    Person.prototype.printName = function(){
        console.log(this.name)
    }
    Person.prototype.printAge = function(){
        console.log(this.age)
    }
    function Student(name,age){
        // 继承 Person 的属性
        Person.call(this,name,age)
    }
    function create(prototype){
        function F(){}
        F.prototype = prototype
        return new F()
    }
    // 让Student的原型指向一个对象,该对象的原型指向了Person.prototype,通过这种方式继承 Person 的方法
    Student.prototype = create(Person.prototype)
    Student.prototype.printAge = function(){
        console.log(this.age)
    }
    let student = new Student('jerry',12)
    student.printName() // "jerry"
    student.printAge() // "12"

3、混合模式

    function Person(name,age){
        this.name = name
        this.age = age
    }
    Person.prototype.printName = function(){
        console.log(this.name)
    }
    function Student(name,age){
        // 继承 Person 的属性
        Person.call(this, name, age)
    }
    function create(prototype){
        function F(){}
        F.prototype = prototype
        return new F()
    }
    // 让Student的原型指向一个对象,该对象的原型指向了Person.prototype,通过这种方式继承 Person 的方法
    Student.prototype = create(Person.prototype)
    Student.prototype.printAge = function(){
        console.log(this.age)
    }
    let student = new Student('jerry', 12)
    student.printName() // "jerry"
    student.printAge() // 12

4、工厂模式

    function Person(name, age){
        let person = new Object()
        person.name = name
        person.age = age
        person.printName = function(){
            console.log(this.name)
        }
        person.printAge = function(){
            console.log(this.age)
        }
        return person
    }
    let person = Person('jerry',12)
    person.printName()
    person.printAge()

5、单例模式

    let Singleton = (function(){
        let instantiated
        function init(){
            /*定义单例代码*/
            return{
                publicMethod: function(){
                    console.log("Hello World");
                },
                publicProperty: "Test"
            }
        }
        return{
            getInstance: function(){
                if(!instantiated){
                    instantiated = init()
                }
                return instantiated
            }
        }
    }())
    Singleton.getInstance().publicMethod()

单例之间的通讯:
建立两个独立的对象:jim&&lily,两者之间通过door直接通讯,如果没有新建door,有直接通讯。代码如下:

    let jim = (function(argument){
        let door
        let jimHome = function(msg){
            this.doorbell = msg
        }
        let info = {
            sendMessage: function(msg){
                if(!door){
                    door = new jimHome(msg)
                }
                return door
            },
            coming: function(){
                return "來了來了"
            }
        }
        return info
    }())
    let lily = {
        callJim: function(msg){
            let _xw = jim.sendMessage(msg)
            alert(_xw.doorbell)
            console.log(_xw.doorbell)
            _xw = null // 等待垃圾回收
            let coming = jim.coming()
            console.log(coming)
        }
    }
    lily.callJim("叮咙")

6、发布-订阅模式
订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象。这个主题对象在自身主题变化时,会通知所有订阅者对象,使他们能够自动更新自己的状态。
将一个系统分割成一系列相互协作的类有一个很不好的副作用:需要维护相应对象间的一致性,这样会给维护、扩展和重用都带来不便。当一个对象的改变需要同时改变其他对象,而且他不知道具体有多少对象需要改变时,此时建议使用订阅发布模式。
应用场景:
DOM事件。DOM事件是一种典型的发布-订阅模式,对一个DOM节点的DOM事件进行监听;当操作DOM节点时,触发相应的事件并执行函数。
自定义时间。指定发布者,类似于一个对象(key:value);key表示事件的名称,value是一个数组;发布消息后,遍历value的数组,依次执行订阅者的回调函数。
应用Demo如下:

    let Event = (function(){
        var events = {}
        function on(evt, handler){
            events[evt] = events[evt]||[];
            events[evt].push({
                handler:handler
            })
        }
        function fire(evt,args){
            if(!events[evt]){
                return
            }
            for(var i=0;i<events[evt].length;i++){
                events[evt][i].handler(args)
            }
        }
        function off(evt){
            delete events[evt]
        }
        return {
            on: on,
            fire: fire,
            off: off
        }
    }())
    Event.on('change', function(val){
        console.log('change事件,value is' + val)
    })
    Event.on('click', function(val){
        console.log('click事件,value is '+ val)
    })
    Event.fire('change', 'jerry1')
    Event.fire('click', 'jerry2')
    Event.off('change')

备注:console.log(name, 'name')没有报错,是因为name是浏览器的窗口变量名,已存在于浏览器内部。

相关文章:

  • 区块链将重新定义世界
  • 时间复杂度与空间复杂度分析
  • 面试必备指南:你的系统如何支撑高并发?
  • [学习笔记]虚树
  • Iterator 和 for...of 循环
  • SharePoint:如何使用PowerShell批量删除名称以XXX开始的List?
  • Kafka之与Spring集成
  • python 模块一览
  • 《流浪地球》:一个程序员用代码拯救了世界,真硬核!
  • 500位软件开发工程师的声音:微服务和CI/CD依旧是最爱
  • 机器学习进阶-图像形态学操作-膨胀操作 1.cv2.dilate(进行膨胀操作)
  • 用Python写一份独特的元宵节祝福
  • Java开源诊断工具 Arthas 发布v3.1.0
  • 汇编语言第一章检测题
  • 无法打开外网ip链接
  • [NodeJS] 关于Buffer
  • 30天自制操作系统-2
  • CentOS7简单部署NFS
  • docker-consul
  • idea + plantuml 画流程图
  • Java深入 - 深入理解Java集合
  • mysql 数据库四种事务隔离级别
  • php的插入排序,通过双层for循环
  • SQLServer插入数据
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 大整数乘法-表格法
  • 分布式事物理论与实践
  • 一个项目push到多个远程Git仓库
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 与 ConTeXt MkIV 官方文档的接驳
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • 字符串匹配基础上
  • 【干货分享】dos命令大全
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • Spring Batch JSON 支持
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • #WEB前端(HTML属性)
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • $(selector).each()和$.each()的区别
  • (1)(1.13) SiK无线电高级配置(六)
  • (2)MFC+openGL单文档框架glFrame
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (十八)SpringBoot之发送QQ邮件
  • (一)基于IDEA的JAVA基础10
  • (转)scrum常见工具列表
  • .FileZilla的使用和主动模式被动模式介绍
  • .NET 同步与异步 之 原子操作和自旋锁(Interlocked、SpinLock)(九)
  • .net 托管代码与非托管代码
  • /etc/motd and /etc/issue
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • [20180312]进程管理其中的SQL Server进程占用内存远远大于SQL server内部统计出来的内存...