JavaScript 设计模式从零开始(上
简介: 本文主要讲单例模式,策略模式,代理模式,本文内容均参考曾探所著《Javascript设计模式与开发实践一书》
1、单例模式
单例模式的定义是: 保证一个类只有一个实例,并提供一个全局访问它的全局访问点
创建单例模式的思路是:使用一个变量来记录这个对象是否已经被创建过,如果已经创建则直接返回这个对象
标准单例模式
var Singleton = function(name){
this.name = name
}
Singleton.prototype.getName = function(){
return this.name
}
Singleton.getInstance = function(name){
if(!this.instance){
this.instance = new Singleton(name)
}
return this.instance
}
var a = Singleton.getInstance('single1')
var b = Singleton.getInstance('single2')
console.log(a === b)
或者通过闭包创建
var Singleton = function(name){
this.name = name
}
Singleton.prototype.getName = function(){
return this.name
}
Singleton.getInstance = (function(name){
var instance = null
if(!instance){
instance = new Singleton(name)
}
return instance
})()
var a = Singleton.getInstance('single1')
var b = Singleton.getInstance('single2')
console.log(a === b)
通用惰性单例
//创建单例的函数
var getSingle = function(fn){
var result
return function(){
return resulr || (result = fn.apply(this,arguments))
}
}
//创建单个弹窗 以fn参数的形式传入 getSingle
var createLoginLayer = function(){
var div = document.createElement('div')
div.innerHTML = "我是登录浮窗"
div.style.display = "none"
document.body.appendChild(div)
return div
}
var createSingleLoginLayer = getSingle(createLoginLayer)
let loginButton = document.createElement('button')
loginButton.innerHTML = "登录"
loginButton.id = "login-button"
document.body.appendChild(loginButton)
//点击登录按钮 创建登录浮窗
document.getElementById('login-button').onclick = function(){
var loginLayer = createSingleLoginLayer()
loginLayer.style.display = "block";
}
利用上面的例子创建单例的iframey也很方便
2 、策略模式
策略模式的定义是: 定义一系列的算法,把他们一个一个封装起来,并且可以使他们相互替换。
比如: 播放视频我们可以选择使用flash插件也可以使用HTML5 的video
突然有点想开摆 哈哈 先写完这篇吧,最近要学uniapp 和深入学习一下ts,还有git的博客没有写
心情乱遭遭的
代码实例:计算年终奖金,根据不同的级别发送不同的奖金
//策略对象
const strategies = {
S: function(salary){
return salary * 4
},
A: function(salary){
return salary * 3
},
B: function(salary){
return salary * 2
}
}
let caculateBonus = function(level,salary){
return strategies[level](salary)
}
console.log(caculateBonus('S',20000));
console.log(caculateBonus('A',10000));
我们一般的表单校验是通过if eles 来实现的
代码示例:用策略模式进行表单校验
//策略模式实现表单校验 strategy.js
let registerForm = document.getElementById('register-form')
let inputName = document.getElementById('user-name')
let inputPassword = document.getElementById('password')
let inputPhone = document.getElementById('phone')
const FormStrategies = {
isEmpty: function (value, errorMsg) {
if (value === '') {
return errorMsg
}
},
minLength: function (value, length, errorMsg) {
if (value.length < length) {
return errorMsg;
}
},
isMobile: function (value, errorMsg) {
if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
return errorMsg;
}
}
}
//验证函数
const validateFunc = function () {
let validator = new Validator() //创建一个validator对象
validator.add(inputName, 'isEmpty','名字不能为空')
validator.add(inputPassword, 'minLength:6','密码长度不能小于6') //密码长度不能小于6
validator.add(inputPhone, 'isMobile','手机格式不正确') //手机号码格式不正确
let errorMsg = validator.start() //获得校验结果
return errorMsg
}
//定义 Validator 类
class Validator {
constructor() {
this.cache = []
}
//定义添加方法
add(dom, rule, errorMsg) {
let ary = rule.split(':') //把 strategy 和 参数分开
this.cache.push(function () { //存储校验函数
let strategy = ary.shift()
ary.unshift(dom.value)
ary.push(errorMsg)
return FormStrategies[strategy].apply(dom, ary) //调用策略对象校验
})
}
//遍历cache 的规则进行校验
start() {
// this.cache.forEach((validateFunc)=>{
// let msg = validateFunc()
// if(msg){
// return msg
// }
// })
console.log('start validate')
for (let i = 0; i < this.cache.length; i++) {
let msg = this.cache[i]()
if (msg) {
return msg
}
}
}
}
registerForm.onsubmit = function(){
//提交表单
var errorMsg = validateFunc() //校验表单
if (errorMsg) {
alert(errorMsg)
return false; //阻止提交
}
}
strategy.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Strategy 策略模式</title>
</head>
<body>
<div>
<form action="http://localhost:8088/register.php" method="post" id="register-form">
<label for="name">名字:
<input type="text" placeholder="请输入名字" name="user_name" value="" id="user-name">
</label>
<br>
<label for="password">密码:
<input type="password" name="password" id="password" value="" id="password">
</label>
<br>
<label for="phone">手机号码
<input type="text" placeholder="请输入手机号码" name="phone" value="" id="phone">
</label>
<br>
<input type="submit" value="提交">
</form>
<script src="./strategy.js"></script>
</div>
</body>
</html>
php后台代码 可不写
速装一个 wamp 或 xampp
配置系统环境变量
cd ‘./php’ register.php 根目录
php -S localhost:8088
<!DOCTYPE html>
<html>
<body>
<?php
echo "Hello World!";
echo $_POST['user_name'];
echo $_POST['password'];
echo $_POST['phone'];
?>
</body>
</html>
策略模式优点 避免大量 if eles 重复代码,可复用
缺点 需要封装策略对象,必须对不同 的 strategy有所了解
3、代理模式
代理模式是为一个对象提供一个代用品或占位符 以便控制对它的控制访问
讲到代理模式不由想到 es6 的Proxy 这里提供一个 大佬博客的传送门,有兴趣的可以看看
es6 Proxy