热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

javascript设计模式_你应了解的4种JS设计模式

javascript设计模式_你应了解的4种JS设计模式,Go语言社区,Golang程序员人脉社


每个JS开发者都力求写出可维护、复用性和可读性高的代码。随着应用不断扩大,代码组织的合理性也越来越重要。设计模式为特定环境下的常见问题提供了一个组织结构,对于克服这些挑战起到至关重要的作用。


Javascript 网页开发者在创建应用时,频繁地跟设计模式打交道(甚至在不知情的情况下)。


尽管特定环境下有各种各样的设计模式,JS 开发者还是倾向于使用一些习惯性的模式。


在这篇文章中,我将讨论这些常见的设计模式,展出优化代码库的方法,并深入解读Javascript的内部构件。


本文讨论的设计模式包括这几种:


  • 模块设计模式
  • 原型模式
  • 观察者模式
  • 单例模式

尽管每种模式都包含很多属性,这里我强调以下几点:


  • 上下文: 设计模式的使用场景
  • 问题: 我们尝试解决的问题是什么?
  • 解决方法: 使用设计模式如何解决我们提出的问题?
  • 实施: 实施方案看起来怎样?

1、模块设计模式


JS模块化是使用最普遍的设计模式,用于保持特殊的代码块与其它组件之间互相独立。为支持结构良好的代码提供了松耦合。


对于熟悉面向对象的开发者来说,模块就是JS的 “类”。封装是“类”的众多优点之一,可以确保它本身的状态和行为不被其它的类访问到。模块设计模式有公有和私有两种访问级别(除此之外,还有比较少为人知的保护级别、特权级别)。


考虑到私有的作用域,模块应该是一个立即调用函数(IIFE) ,也就是说,它是一个保护其私有变量和方法的闭包。(然而,它返回的却不是一个函数,而是一个对象)。


它的写法就是这样的:




e5d8cfe37aae129cae28677a026a277a.png

我们在返回一个对象之前,先初始化一下私有的变量和方法。由于作用域不同,闭包外面的代码是无法访问到闭包内的私有变量的。一起来看下更具体的实现方法:




241ca9a30382c83d5ca72a665e90c9d8.png

请注意 callChangeHTML 是在返回的对象中绑定的,因此可以访问到 HTMLChanger 这个命名空间内的变量。然而,在模块外面,是不能访问到闭包里面的 contents 的。


揭示性模块模式


模块模式的另一种变体称为 揭示性模块模式,它主要是为了在保持封装性的同时,揭示在对象字面量中返回的特定的变量和方法。直接的实现方式类似这样:




ab7e3c75badb81c71f48772c7530606a.png

尽管这样看起来更加简洁,但它是有明显不足的 -- 不能引用私有变量。这会给单元测试带来一定的挑战。类似地,公有行为也是不可重写的。


2、原型设计模式


JS开发者要么把 原型 和 原型继承 相互混淆,要么在他们的代码里面直接使用原型。原型设计模式依赖于Javascript原型继承. 原型模式主要用于为高性能环境创建对象。


被创建的对象是从传下来的原对象克隆(浅克隆)出来的。原型模式的一种使用场景,是执行一个扩展性的数据库操作来创建一个对象,把该对象用于应用的其他层面。如果其他流程需要用到这个对象,我们不需要大量地操作数据库,只要克隆一下之前创建的对象就可以了。与其实质性地操作数据库,不如从之前创建的对象克隆一个更具优势。




cfd91adeaeac9a81d7324150a766e0d3.png

_Wikipedia_ 原型设计模式图解


UML 描述了原型交互是如何被用于克隆具体的代码实施方案的。


要克隆一个对象,必须存在一个构造器来实例化第一个对象。接下来,通过使用 prototype 的变量和方法来绑定对象的结构。一起来看下基本的示例:




5858723e7d2f72c4f2f782a26e7e9275.png

构造器 TeslaModelS 允许创建一个简单的 TeslaModelS 对象。对于一个新创建的 TeslaModelS 对象,它将保持构造器初始化的状态。此外,它也很简单的持有 go 和 stop 这两个方法,因为这两个方法是在 prototype 声明的。在原型上拓展方法,还可以这样写:




ea68e4876db235468a65ba29137d7f1d.png

揭示性原型模式


类似于模块模式,原型模式也有一个 揭示性模式。揭示性原型模式 通过返回一个对象字面量,对公有和私有的成员进行封装。


由于我们返回的是一个对象,我们将在原型对象上添加 function 的前缀。通过对以上例子进行改写,我们可以选择在当前的 prototype 暴露哪些方法或变量,以此来保护它们的访问层级。




5497da03996d305acc1b1259374ffa81.png

请注意 stop 和 go 两个方法是被隔开的,因为他们在所返回的对象作用域之外。由于 Javascript 本身支持原型继承,也就没必要重写基本的功能了。


3、观察者设计模式


很多时候,当应用的一部分改变了,另一部分也需要相应更新。在 AngularJs 里面,如果 $scope 被更新,就会触发一个事件去通知其他组件。结合观察这模式就是:如果一个对象改变了,它只要派发 broadcasts 事件通知依赖的对象它已经改变了则可。


又一个典型的例子就是 model-view-controller (MVC) 架构了;当 model 改变时, 更新相应的 view。这样做有一个好处,就是从 model 上解耦出 view 来减少依赖。




e4294c03b33fb8cde8d971d2794440c2.png

Wikipedia 观察者设计模式


如 UML 图表所示,subject、observer, and concrete objects 是必不可少的。 subject 包含对每个具体观察者的引用,以便传递改动信息。观察者本身是一个抽象的类,使得具体的观察者可以执行通讯方法。


一起来看下 AngularJS 的示例,在事件管理上应用了观察这模式。




ebe2be9b1e1f2cefd17b71ca5da4cd2f.png

使用观察者模式,重要的一点就是要区分独立的对象或者 subject(主体)。


在看到观察者模式众多优点的同时,我们必须注意到它的一个缺点:随着观察者数量的增加,应用的性能会大大降低。大家都比较熟悉的观察者就是 watchers 。 在AngularJS中,我们可以 watch 变量、方法和对象。$digest 循环更新,当一个作用域内对象被修改时,它就把新的值告诉每个监听者。


我们可以在JS中创建自己的主体和观察者。一起来看下下面的代码是如何运行的:




cd00ef1291ef874c2763ae3b23a144ce.png

发布、订阅模式


然而,发布、订阅模式是采用一个话题来绑定发布者和订阅者之间的关系,订阅者接收事件通知,发布者派发事件。该事件系统支持定义特殊应用的事件,可以传递包含订阅者本身需要的自定义参数。这样做主要是为了避免订阅者和发布者之间的依赖。


这里有别于观察者模式的是,任何订阅者都可以通过恰当的事件处理器来注册并接受发布者广播的通知。


很多开发者选择把 发布订阅模式 和 观察者模式 结合起来用,尽管他们最终的目标只有一个。发布订阅模式中的订阅者是通过一些通讯媒介被告知的,而观察者则是通过执行事件处理器来获得消息通知。


在 AngularJs, 订阅者使用 $on(event、cbk) 来订阅一个事件,发布者则使用$emit(‘event’, args) 或者 $broadcast(‘event’, args) 来发布一个事件。


4、单例模式


单例模式只允许实例化一个对象,但是相同的对象,会用很多个实例。单例模式制约着客户端创建多个对象。第一个对象创建后,就返回实例本身。


单例模式比较少用,很难找到实际开发的例子。使用一个办公室打印机的例子吧。假设办公室有10个人,他们都用到打印机,10台电脑共享一部打印机(一个实例)。通过分享一部打印机,他们共享相同的资源。




20072b9d7269fb79a14fb39d8a66e206.png

create 这个方法是私有的,因为我们不希望它被外部人员访问到,然而,getInstance 方法是公有的。每个办公人员都可以实例化一个 printer,只需要这样调用一下:




5ca3d6ff407d63e35094926fb545887d.png

单例模式在 AngularJS 相当流行,最常见的是作为 services、factories、和 providers。它们维护状态,提供资源访问,创建两个实例摆脱一个共享的service/factory/provider。


在多线程的应用中,当多个线程尝试去访问同个资源时,就会出现 竞争状态。单例模式会受到竞争状态的干扰,比如在没有初始化实例的情况下,两个线程会创建两个对象,而不是返回一个实例。这与单例模式的目的是相悖的。因此,开发者在多线程应用里面使用单例模式时,必须清楚同步性。


总结


设计模式经常用于比较大型的应用,想知道哪种模式更具优势,来实践吧。


在构建任何应用之前,都应该全面地考虑每个角色,以及它们之间存在的关系。在回顾 模块模式、原型模式、观察者模式 和 单例模式 之后,你应该能够区分它们,并且在实际开发中使用它们了。



我自己是一名从事了多年开发的web前端老程序员,目前辞职在做自己的web前端私人定制课程,今年年初我花了一个月整理了一份最适合2019年学习的web前端学习干货,各种框架都有整理,送给每一位前端小伙伴,想要获取的可以关注我的头条号并在后台私信我:前端,即可免费获取。

译者 | 旭日云中竹


原文 | http://codetrick.net/p/Hkoj47YN0/4-Javascript-design-patterns-you-should-know/





推荐阅读
  • wpf+mvvm代码组织结构及实现方式
    本文介绍了wpf+mvvm代码组织结构的由来和实现方式。作者回顾了自己大学时期接触wpf开发和mvvm模式的经历,认为mvvm模式使得开发更加专注于业务且高效。与此同时,作者指出mvvm模式相较于mvc模式的优势。文章还提到了当没有mvvm时处理数据和UI交互的例子,以及前后端分离和组件化的概念。作者希望能够只关注原始数据结构,将数据交给UI自行改变,从而解放劳动力,避免加班。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • Todayatworksomeonetriedtoconvincemethat:今天在工作中有人试图说服我:{$obj->getTableInfo()}isfine ... [详细]
  • 本文介绍了ASP.NET Core MVC的入门及基础使用教程,根据微软的文档学习,建议阅读英文文档以便更好理解,微软的工具化使用方便且开发速度快。通过vs2017新建项目,可以创建一个基础的ASP.NET网站,也可以实现动态网站开发。ASP.NET MVC框架及其工具简化了开发过程,包括建立业务的数据模型和控制器等步骤。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
  • 本文讨论了在ASP中创建RazorFunctions.cshtml文件时出现的问题,即ASP.global_asax不存在于命名空间ASP中。文章提供了解决该问题的代码示例,并详细解释了代码中涉及的关键概念,如HttpContext、Request和RouteData等。通过阅读本文,读者可以了解如何解决该问题并理解相关的ASP概念。 ... [详细]
  • SpringMVC工作流程概述
    SpringMVC工作流程概述 ... [详细]
author-avatar
素人1963_497
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有