设计模式代码片段

判断类型

const Type = {};
['String', 'Array', 'Number'].map((type) => {
  Type[`is${type}`] = (obj) => Object.prototype.toString.call(obj) === `[object ${type}]`
})

console.log(Type.isString('123'))
console.log(Type.isArray([1,2,3]))
console.log(Type.isNumber(123))

动态单例模式

const myApp = {
  namespace(name) {
    var current = this
    var parts = name.split('.')
    for (let p of parts) {
      if (!current[p]) {
        current[p] = {}
      }
      current = current[p]
    }
  }
}
myApp.namespace('dom.style.classname')

//上面的代码相当于
var myApp={
  dom:{
    style:{
      classname:{}
    }
  }
}

创建唯一登录框(单例模式)

// 通用单例模式函数
var singleton = function(handler) {
  let result
  return function() {
    return result || (result = handler.apply(this, arguments))
  }
}

var createLoginLayer = function() {
  div = document.createElement('div');
  div.innerHTML = '我是登录浮窗';
  div.style.display = 'none';
  document.body.appendChild(div);
  return div;
}
//组合生成单例模式
const createSingletonLoginLayer =singleton(createLoginLayer);

document.getElementById('loginBtn').onclick = function() {
  const LoginLayer = createSingletonLoginLayer()
  LoginLayer.style.display = 'block';
};

校验器(策略模式)

// strategy策略对象
var strategies = {
  isNonEmpty: 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;
    }
  }
};

// Context类
class Validator {
  #cache = []; //保存校验规则
  add(dom, rule, errorMessage) {
    if (rule instanceof Array) {
      return this.addRules(dom, rule);
    }
    // 把校验的步骤用空函数包装起来,并且放入cache
    this.#cache.push(function () {
      const [strategyProperty, ...args] = rule.split(":"); //分割出需要传递给验证函数的参数
      //将验证逻辑委托给策略对象中的验证函数
      return strategies[strategyProperty].apply(dom, [
        dom.value,
        ...args,
        errorMessage
      ]);
    });
  }
  start() {
    for (let itemFunc of this.#cache) {
      let message = itemFunc();
      if (message) {
        return message;
      }
    }
  }
  addRules(dom, rules) {
    for (let [rule, errorMessage] of rules) {
      this.add(dom, rule, errorMessage);
    }
  }
}

var validator = new Validator(); 
validator.add(registerForm.phoneNumber, "isMobile", "手机号码格式不正确");
validator.add(registerForm.userName, [
    ["isNonEmpty", "用户名不能为空"],
    ["minLength:10", "用户名长度不能小于10位"]
  ]);

预加载图片(代理模式)

var myImage = (function() {
  var imgNode = document.createElement('img');
  document.body.appendChild(imgNode);

  return {
    setSrc: function(src) {
      imgNode.src = src;
    }
  }
})();

var proxyImage = (function() {
  const img = new Image()
  img.onload = function() { // 3. 代理的src加载完成,会触发onload事件
    myImage.setSrc(this.src) // 4. 此时再重新给被代理的节点设置src属性
  }
  return {
    setSrc(src) {
      myImage.setSrc('loading.png')//1.先让node节点预先加载loading图
      img.src = src //2.设置代理的src属性
    }
  }
})()

proxyImage.setSrc('http://xxxx') // proxyImage代理了myImage的访问,并且加入额外的预加载操作

缓存代理(代理模式)

var mult = function(...rest) {
  let a = 1
  mult = function(...rest) {
    for (let i of rest) {
      console.log("这里是复杂的计算")
      a *= i
    }
    return a
  }
  return mult(...rest)
}


var proxyMult = (function() {
  let cache = {}
  return function(...rest) {
    let property = rest.join(',')
    if (property in cache) {
      return cache[property]
    }
    return cache[property] = mult(...rest)
  }
})()

console.log(proxyMult(1, 2, 3))
console.log(proxyMult(1, 2, 3))

发布订阅模式

class eventHub {
  #cache = {};
  //订阅事件
  listen(key, fn) {
    if (key in this.#cache === false) {
      this.#cache[key] = [];
    }
    this.#cache[key].push(fn);
  }
  // 发布事件
  trigger(key, ...rest) {
    if (!this.#cache[key] || this.#cache[key].length === 0) {
      return false;
    }
    for (let fn of this.#cache[key]) {
      fn.call(this, ...rest);
    }
  }
  //删除订阅事件
  remove(key, fn) {
    if (!key) {
      return false;
    }
    //如果没传递指定的函数,则删除全部订阅
    if (!fn) {
      this.#cache[key] = [];
    }
    const len = this.#cache[key].length;
    // 遍历cache,删除指定的函数
    for (let i = 0; i < len; i++) {
      let _fn = this.#cache[key][i];
      if (fn === _fn) {
        this.#cache[key].splice(i, 1);
        break;
      }
    }
  }
}