本文共 3855 字,大约阅读时间需要 12 分钟。
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); // 结果为trueconsole.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)); // 输出:24console.log(proxyMult(1, 2, 3, 4)); // 输出:24console.log(proxyPlus(1, 2, 3, 4)); // 输出:10console.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;};
转载地址:http://beuni.baihongyu.com/