JavaScript设计模式
2021-02-28 21:23:32 429 举报
AI智能生成
前端 设计模式
作者其他创作
大纲/内容
前置知识
面向对象的一些概念
public
可以自由的访问程序里定义的成员<br><br>在TypeScript里,成员都默认为 public<br>
private
不能在声明它的类的外部访问
protected
不能在声明它的类的外部访问<br><br>但是 protected成员在派生类中仍然可以访问
static
属性存在于类本身上面而不是类的实例上<br><br>如同在实例属性上使用 <b>this. </b>前缀来访问属性一样,这里我们使用 <b>类名. </b>来访问静态属性<br>
abstract
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化
abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法
抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
constructor
面向对象编程和面向对象设计的五个基本原则
单一功能原则
开放封闭原则
里式替换原则
接口隔离原则
依赖反转原则
创建型
构造器模式
作用
创建对象<br>抽象了每个对象实例的变与不变,不变得字段名称,变得是字段的值<br>
如何使用
构造函数
工厂模式
是什么
工厂模式其实就是将创建对象的过程单独封装
作用
抽象不同构造函数(类)之间的变与不变<br>工厂模式的目的,就是为了实现无脑传参<br>
简单工厂
如何使用
声明一个函数及其N个参数,在函数内部判断不同的参数,从而生成不同的对象
抽象工厂
层级
抽象工厂(抽象类,它不能被用于生成具体实例)
具体工厂(用于生成产品族里的一个具体的产品)
抽象产品(抽象类,它不能被用于生成具体实例)
具体产品(用于生成产品族里的一个具体的产品所依赖的更细粒度的产品)
单例模式
含义
保证一个类仅有一个实例,并提供一个访问它的全局访问点
作用
不管创建多少次,它都只返回第一次所创建的那唯一的一个实例
如何做
判断自己是否已经创建过一个实例
静态方法版本
闭包版本
面试题
实现一个 Storage
实现一个全局的模态框
原型模式
是什么
只要我们还在借助Prototype来实现对象的创建和原型的继承,那么我们就是在应用原型模式
为什么使用
原型模式不仅是一种设计模式,<br>还是一种<b>编程范式</b>(programming paradigm),<br>是 JavaScript 面向对象系统实现的根基
组成
原型
构造函数上存在 prototype 属性
指向
原型对象
实例上存在 __proto__属性
指向
原型对象
原型上存在 constructor 属性
指向
构造函数
原型链
面试题
JS中的深拷贝
JSON.stringify
无法处理 function
无法处理正则
........
递归 & data.hasOwnProperty(key)
逻辑
调用深拷贝方法,若属性为值类型,则直接返回;若属性为引用类型,则递归遍历
除了考虑 Array、Object,还需要考虑一些其它的数据结构(Map、Set 等);此外还有一些极端 case(循环引用等)
结构型
装饰器模式
是什么
在不改变原对象的基础上,通过对其进行包装拓展,使原有对象可以满足用户的更复杂需求
不想去关心它已有的业务逻辑是啥样的
对它已有的功能做个拓展,只关心拓展出来的那部分新功能如何实现
如何使用
@语法糖
@语法糖只能修饰类或者类的方法<br><br>如果需要修饰函数,可以使用高阶函数的方式
代码中可以干什么
装饰类
原理: 给类自身添加属性
装饰类里面的方法
原理: 给类的原型对象添加属性
装饰函数
原理:高阶函数
场景
React中的HOC
Redux connect函数
调用 connect 方法来把状态和组件绑在一起
适配器模式
含义
把一个类的接口变换成客户端所期待的另一种接口,以解决不兼容的问题
优点
暴露给用户的都是十分简单的统一的东西——统一的接口,统一的入参,统一的出参,统一的规则
如何做
不仅调用的接口名是同一个,连入参、出参的格式都只需要掌握同一套
场景
http 适配器
xhr 适配器
fetch的封装
ajax封装
axios封装
代理模式
what
在某些情况下,出于种种考虑/限制,一个对象不能直接访问另一个对象,需要一个第三者(代理)牵线搭桥从而间接达到访问目的,这样的模式就是代理模式
why
既可以是为了加强控制、拓展功能、提高性能,<br>也可以仅仅是为了优化我们的代码结构、实现功能的解耦。<br>无论是出于什么目的,这种模式的套路就只有一个—— A 不能直接访问 B,A 需要借助一个帮手来访问 B,这个帮手就是代理器
真实例子
VPN
ES6中的Proxy
前端场景
事件代理
案例: 考虑到事件本身具有“冒泡”的特性,当我们点击 a 元素时,点击事件会“冒泡”到父元素 div 上,从而被监听到。如此一来,点击事件的监听函数只需要在 div 元素上被绑定一次即可,而不需要在子元素上被绑定 N 次——这种做法就是事件代理,它可以很大程度上提高我们代码的性能
虚拟代理
案例: 实现前端图片预加载
明确几个概念
图片懒加载
它是针对图片加载时机的优化:在一些图片量比较大的网站,比如电商网站首页,或者团购网站、小游戏首页等。<br>如果我们尝试在用户打开页面的时候,就把所有的图片资源加载完毕,那么很可能会造成白屏、卡顿等现象<br><br>此时我们会<b>采取“先占位、后加载”的方式来展示图片</b> —— 在元素露出之前,我们给它一个 div 作占位,当它滚动到可视区域内时,再即时地去加载真实的图片资源,这样做既减轻了性能压力、又保住了用户体验。<br>
图片懒加载 先于图片预加载
图片预加载
预加载主要是为了避免网络不好、或者图片太大时,页面长时间给用户留白的尴尬。<br><br>常见的操作是先让这个 img 标签展示一个占位图,然后创建一个 Image 实例,<br><br>让这个 Image 实例的 src 指向真实的目标图片地址、观察该 Image 实例的加载情况 —— 当其对应的真实图片加载完毕后,即已经有了该图片的缓存内容,再将 DOM 上的 img 元素的 src 指向真实的目标图片地址。<br><br>此时我们直接去取了目标图片的缓存,所以展示速度会非常快,从占位图到目标图片的时间差会非常小、小到用户注意不到,这样体验就会非常好了
缓存代理
案例: 对传入的参数进行求和--通过闭包存储已计算的值,每次计算前就进行比较
保护代理
在访问层面做文章,在 getter 和 setter 函数里去进行校验和拦截,确保一部分变量是安全/无法访问的
Proxy,就是为拦截而生的,所以我们目前实现保护代理时,考虑的首要方案就是 ES6 中的 Proxy
行为模型
策略模式
what
定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换
算法提取
某一个功能函数的逻辑
算法封装
把某一功能点对应的逻辑给提出来
分发优化
场景
将if else或switch 改写为对象映射的方式
状态模式
观察者模式
what
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新
why
是所有 JavaScript 设计模式中使用频率最高,面试频率也最高的设计模式
这种模式不仅在业务开发中遍地开花,在日常生活中也是非常常见的
即便是两个分离的、毫不相关的模块,也可以实现数据通信
组成
发布者
增加订阅者
通知订阅者
移除订阅者
订阅者
被通知
去执行
面试题
Vue数据双向绑定(响应式系统)的实现原理
实现一个Event Bus/ Event Emitter (发布-订阅模式)
与发布 - 订阅模式的比较
本质
没有区别
区别
在于是否存在第三方、发布者能否直接感知订阅者
发布 - 订阅模式的
含义
发布者不直接触及到订阅者、而是由统一的第三方来完成实际的通信的操作,叫做发布-订阅模式
例子
老王把需求文档上传到了公司统一的需求平台上,需求平台感知到文件的变化、自动通知了每一位订阅了该文件的开发者
发布者完全不用感知订阅者,不用关心它怎么实现回调方法,事件的注册和触发都发生在独立于双方的第三方平台(事件总线)上。发布-订阅模式下,实现了完全地解耦。
观察者模式
含义
发布者直接触及到订阅者的操作,叫观察者模式
例子
老王把所有的开发者拉了一个群,直接把需求文档丢给每一位群成员
并没有完全地解决耦合问题——被观察者必须去维护一套观察者的集合,这些观察者必须实现统一的方法供被观察者调用
迭代器模式
what
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示
它就解决这一个问题——遍历
ES6约定,任何数据结构只要具备Symbol.iterator属性(这个属性就是Iterator的具体实现,它本质上是当前数据结构默认的迭代器生成函数),就可以被遍历——准确地说,是被for...of...循环和迭代器的next方法遍历。 事实上,for...of...的背后正是对next方法的反复调用。<br><br>在ES6中,针对Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象这些原生的数据结构都可以通过for...of...进行遍历
场景
遍历类数组
例子: 循环`const aNodes = document.getElementsByTagName('a')`
案例
ES6 迭代器(Iterator)
面试题
实现一个迭代器生成函数
ES6方式
ES5方式
0 条评论
下一页