js设计模式(1)---单例模式、策略模式、代理模式、迭代器

js设计模式系列(1)----此文主要是对<<JavaScript设计模式与开发实践>>一书的范例摘要。

一、单例模式

1、js没有类的概念,如果是字面量对象的方式,那么直接创建的字面量对象就是一个单例对象,如果我们需要兼顾构造函数创建对象以及惰性加载的方式,就可以采用闭包缓存已经创建的对象,详见下面案例:

var getSingle = function(fn) {  // fn是创建对象的方法
  var result ;
  return function() {
    return result || (result = fn.apply(this, arguments)) //result不存在,就创建
  }
}

// 调用getSingle方法,传入一个创建对象的方法。
var getInstance = getSingle(function(str) {
  return Symbol(str);
});

// getInstance 就可以用来创建对象

var a1 = getInstance('div');
var a2 = getInstance('div');

console.log(a1 == a2); // 结果为true

console.log(Symbol('xx')===Symbol('xx')); // false ,如果创建了二次Symbol对象就肯定是false,这说明只创建了一次symbol对象。

二、策略模式 

策略模式,就是定义一系列的算法,把每一个算法封装成策略类,并且可以使他们互相替换,我们先看看类java预言实现的策略模式


// 2倍绩效的策略(类)
var performanceTwo = function () { }
performanceTwo.prototype.calculate = function (salary) {
  return salary * 2;
}

// 3倍绩效的策略(类)
var performanceThree = function () { };
performanceThree.prototype.calculate = function (salary) {
  return salary * 3;
}

// 管理类 (使用策略类的调用者)
var Manager = function (salary) {
  this.salary = salary; // 原始工资
  this.strategy = null;
};

// 设置策略对象
Manager.prototype.setStrategy = function (strategy) {
  this.strategy = strategy;
};

// 得到最终工资 : 使用传入的策略对原始工资作为参数进行计算。
Manager.prototype.getBonus = function () { 
  return this.strategy.calculate(this.salary);
};

var manager = new Manager(1000);
manager.setStrategy(new performanceThree());
console.log(manager.getBonus())
manager.setStrategy(new performanceTwo());
console.log(manager.getBonus());

2、js方法本身就可以作为参数进行传递,即定义不同算法的方法可以随意替换,只要返回值和参数类型符合运行不报错即可,下面演示js的策略模式。

var strategies = {
  "S": function (salary) {
    return salary * 4;
  },
  "A": function (salary) {
    return salary * 3;
  },
  "B": function (salary) {
    return salary * 2;
  }
};

var calculateBonus = function (level, salary) {
  return strategies[level](salary);
};

上面把定义策略方法用字符串作为策略组的key,然后调用时,传key值就可以取到对应的策略方法。

三·、代理模式

 其实上面单例模式就是利用了代理模式,扩展了创建对象方法的缓存能力,下面实现一个利用js代理模式缓存方法执行结果的案例。

// 创建缓存方法执行结果的代理方法(类)
var createProxyFn = function (fn) {
  var cache = {};
  return function () {
    var args = Array.prototype.join.call(arguments, ',');
    if (args in cache) {
      return cache[args];
    }
    return cache[args] = fn.apply(this, arguments);
  }
};
// 乘法函数
var mult = function () {
  var a = 1;
  for (var i = 0; i < arguments.length; i++) {
    a = a * arguments[i];
  }
  return a;
};
// 加法函数
var plus = function () {
  var a = 0;
  for (var i = 0; i < arguments.length; i++) {
    a = a + arguments[i];
  }
  return a;
};

// 测试
var proxyMult = createProxyFn(mult);
var proxyPlus = createProxyFn(plus);
console.log(proxyMult(1, 2, 3, 4)); // 输出:24
console.log(proxyMult(1, 2, 3, 4)); // 输出:24
console.log(proxyPlus(1, 2, 3, 4)); // 输出:10
console.log(proxyPlus(1, 2, 3, 4)); // 输出:10

createProxyFn 方法,就是根据arguments参数拼接标记id,如果此id的结果已经计算过,那么从缓存中取,否则,重新计算并且把结果赋值给对应id的缓存属性。

四、迭代器

// 迭代器模式

// 1、显示迭代的方式,即把迭代元素遍历,用一个函数参数进行处理。
var each_one = function (arr, fn) {
  for (let i = 0; i < arr.length; i++) {
    fn(arr[i], i);
  }
}

// 显示迭代的使用
each_one([1, 2, 3], function (obj, index) {
  console.log(obj, index);
});

// 2、外部迭代器:主要是闭包内维护一个pos变量,来判断获取当前迭代的对象。
var Interator = function (obj) {
  var pos = 0;
  var next = function () {
    pos += 1;
  }
  var hasNext = function () {
    pos >= obj.length;
  }
  var getCurrent = function () {
    return obj[pos];
  };
  return {
    next,
    hasNext,
    getCurrent
  }
}

// 外部迭代器的使用
var interator = Interator([1, 2, 3]);
while (interator.hasNext()) {
  interator.next();
  console.log(interator.getCurrent());
};

// 3、jquery 迭代器 ()
$.each = function (obj, callback) {
  var value,
    i = 0,
    length = obj.length,
    isArray = isArraylike(obj);
  if (isArray) { // 迭代类数组
    for (; i < length; i++) {
      value = callback.call(obj[i], i, obj[i]);
      if (value === false) {
        break;
      }
    }
  } else {
    for (i in obj) { // 迭代 object 对象
      value = callback.call(obj[i], i, obj[i]);
      if (value === false) {
        break;
      }
    }
  }
  return obj;
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值