写点什么

JavaScript 设计模式之单例模式

用户头像
HaiJun
关注
发布于: 2021 年 05 月 10 日
JavaScript设计模式之单例模式


设计模式开篇

日常开发中,我们都很注重开发技巧,好的开发 技巧可以事半功倍得解决此刻得问题。

那么这些技巧如何来得呢?

我的理解: 经过不断踩坑,解 BUG,总结出来一些处理对应问题解决方案,这就所谓的 技巧

说起设计模式,其实我们日常开始中也经常用到,只是你不知道用的解决方案方案对应的设计模式名称.

学习设计模式的作用

在软件设计中,模式是一些经过了大量实际项目验证的优秀解决方案。熟悉这些模式的程序员,对某些模式的理解也会自然的形成条件反射。当遇到合适的场景出现时,可以快速找到对应的模式来处理当前的问题。

单例模式

定义: 保证 类 仅有 一个实例,并可以全局访问这个实例.

全局变量 不是 单例模式,但是在 JavaScript 中, 我们经常把单例模式当作全局变量使用。

因为它满足单例模式的两点:

  • 创建的全局变量是独一无二的

  • 它可以全局访问这个变量实例


// login.jsvar loginInfo = {   username: '',    token: '',    .......}


//login.vue
import logins from './login.js'
logins.name = this.username
复制代码


但是它也有缺点,容易造成命名空间污染。

定义的全局变量多了, 会覆盖掉之前定义的全局变量,这样会造成不必要的BUG.

如何处理命名空间污染呢?

如何处理呢?

  • 1.使用命名空间

  • 2.使用闭包封装私有变量

命名空间

对象自变量的形式:


// login.jsexport default var loginInfo = {    names:'' ,    token: '',    setName: function (name) {        this.names = name    },    getName: function () {        return this.name    }}

//login.vueimport logins from './login.js'
logins.token = this.token
复制代码

使用闭包封装私有变量

把一些变量封装在闭包内部,只暴露一些接口跟外界通信。

外界是访问不到 内部定义的私有变量的,这样就避免了全局命令污染。


var user = (function () {    //外界是访问不了 _name _age     var _name = '张三',        _age = 22;            return {            //这块留给外界通信用            getUserInfo: function () {                console.log(`姓名为:${_name},年龄为:${_age}`)             }        }})()                                                                                                                                              user.getUserInfo()
复制代码

通用的惰性单例模式

在该执行的情况下,执行操作步骤 / DOM.

优点: 节约了性能。

场景 1

有时候,例如登陆弹窗,在加载首页的同时,它会渲染这个页的全部DOM,如果首页 DOM 内容多,加载速度也会相应的很慢,有很多不需要 DOM 提前渲染。

这时,可以通过惰性单例模式来解决此问题,例如单击了登陆按钮,才会创建登陆弹窗的 DOM,并且记录此次点击状态,如果下次还要打开,只是更改 DOM 的 styledisplay 属性即可。 这样节约了首页加载时间,提升页面性能。


// 定义全局通用单例模式var getSingle = function (fn) {    var result;    return function () {        return result || (result = fn.apply(this, arguments));    }}
// 创建登陆窗口var createLoginLayer = function() { var div = document.createElement('div') div.innerHTML = '登陆框' div.style.display = 'none' document.body.appendChild(div) return div}
// 创建单例模式 登陆框var createSingleLoginLayer = getSingle(createLoginLayer);
document.getElementById('btn').onclick = () => { // 获取单例模式中 返回得登陆框 var loginLayer = createSingleLoginLayer(); // 改变样式 loginLayer.style.display = 'block'}
复制代码
场景 2

创建唯一的 iframe 用于加载第三方页面


var createSingleIframe =  getSingle( function() {    var iframe = document.createElement('iframe');    document.body.appendChild(iframe)    return iframe})
document.getElementById('redirect').onclick = () => { var iframeLayer = createSingleIframe(); iframeLayer.src = 'http://www.baidu.com'}
复制代码

策略模式

定义:

定义一些列的算法,把它们一个个封装起来,留给外界变动的通信参数,相互替换使用。

一个基于策略模式的程序最少由两部分组成:

  • 策略类, 用来封装具体算法,并负责具体计算过程。

  • 环境类, 用来接收用户请求参数,然后将请求参数交给策略类来计算实现

在 JavaScript 实现策略模式

  1. 封装具体的算法计算过程类/对象

  2. 创建环境类,用来将请求传递给封装类来计算

需求 1

例如:

商店里最近有打折优惠活动,但是这个价格不唯一,打折优惠唯一。(这个可以封装成 策略类,用来计算价格)

结算价格,需要将商品名称价格 传递给 策略类 来实现计算。 (一般是通过获取商品id,这里为了演示。这个可以理解成环境类

使用策略模式
var  shopCar = {    'Nike': function( price ) {        return price * 0.4    },    'LiNing': function ( price ) {        return price  * 0.6    },    'AnTa': function ( price ) {        return price  * 0.6    }}
var balance = function(kind,price) { return shopCar[kind](price)}

console.log(`Nike鞋子价格为${balance('Nike',2000)}`)//Nike鞋子价格为800
console.log(`LiNing T短袖价格为${balance('LiNing',300)}`)//LiNing T短袖价格为180
复制代码
你可能会这样写

这样倒是也可以计算出最终结果。

  • 但它包含了大量的 if 语句,这些语句覆盖了所有的逻辑分支。

  • 算法复用性差

  • shop 函数缺乏弹性


var  shop = (kind,price) => {    if ( kind == 'Nike') {        return price * 0.4    }    if ( kind == 'LiNing') {        return price * 0.6    }    if ( kind == 'AnTa') {        return price * 0.6    }}
console.log(shop('LiNing',3000))
复制代码


结语

❤️关注+点赞+收藏+评论+转发❤️,原创不易,鼓励笔者创作更好的文章

发布于: 2021 年 05 月 10 日阅读数: 49
用户头像

HaiJun

关注

还未添加个人签名 2020.04.02 加入

海军,专注Web前端领域开发,分享开发经验与最新前端技术。 微信公众号: 前端自学社区

评论

发布
暂无评论
JavaScript设计模式之单例模式