【阅读笔记】JavaScript设计模式与开发实践2--闭包与单例、策略模式

闭包与高阶函数

Array.prototype.sort 接受一个函数当作参数,用户可以自行在该函数内指定排序方式

// 由小到大排序
let res = [1, 4, 2].sort((a, b) => {
    
    
  return a - b;
});
console.log(res);

Function 扩展函数

通过对 Function 原型执行扩展,可以达到类似装饰器的效果,这也是 AOP 风格的体现

Function.prototype.before = function (beforefn) {
    
    
  var __self = this; // 保存原函数的引用
  return function () {
    
    
    // 返回包含了原函数和新函数的"代理"函数
    beforefn.apply(this, arguments); // 执行新函数,修正this
    return __self.apply(this, arguments); // 执行原函数
  };
};

Function.prototype.after = function (afterfn) {
    
    
  var __self = this;
  return function () {
    
    
    var ret = __self.apply(this, arguments);
    afterfn.apply(this, arguments);
    return ret;
  };
};

var func = function () {
    
    
  console.log(2);
};

func = func
  .before(function () {
    
    
    console.log(1);
  })
  .after(function () {
    
    
    console.log(3);
  });

func(); // 1,2,3

柯里化函数

currying 又称部分求值。一个 currying 的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值

var currying = function (fn) {
    
    
  var args = [];

  // 当调用柯里函数时不带任何参数,直接执行所有栈中函数
  // 当调用柯里函数时带入了参数,就会向args压入一个新的带参函数
  return function () {
    
    
    if (arguments.length === 0) {
    
    
      return fn.apply(this, args);
    } else {
    
    
      [].push.apply(args, arguments);
      return arguments.callee;
    }
  };
};

// 将cost写成一个IIFE函数,之后其将转变为柯里函数
var cost = (function () {
    
    
  var money = 0;
  return function () {
    
    
    for (var i = 0, l = arguments.length; i < l; i++) {
    
    
      money += arguments[i];
    }
    return money;
  };
})();

var cost = currying(cost); // 转化成currying函数

cost(100); // 未真正求值
cost(200); // 未真正求值
cost(300); // 未真正求值
alert(cost()); // 求值并输出:600

单例模式

透明的单例模式

传统单例模式,需要你知道当前对象是单例的,且可以调用 getInstance 方法获取其实例

可以使用代理的方式管理单例,而对象本身不处理代理相关逻辑

var CreateDiv = function (html) {
    
    
  this.html = html;
  this.init();
};

CreateDiv.prototype.init = function () {
    
    
  var div = document.createElement("div");
  div.innerHTML = this.html;
  document.body.appendChild(div);
};

// 使用代理创建以及识别单例
var ProxySingletonCreateDiv = (function () {
    
    
  var instance;
  return function (html) {
    
    
    if (!instance) {
    
    
      instance = new CreateDiv(html);
    }

    return instance;
  };
})();

var a = new ProxySingletonCreateDiv("sven1");
var b = new ProxySingletonCreateDiv("sven2");

alert(a === b); // true

惰性单例

将获取单例的方法单独抽离出来,通过此方法获取对象的单例

var getSingle = function (fn) {
    
    
  var result;
  return function () {
    
    
    return result || (result = fn.apply(this, arguments));
  };
};

策略模式

策略模式的目的就是将算法的使用与算法的实现分离开来

策略模式发展

假设有这么一个场景:需要通过员工名字及其薪水计算奖金

经典方法需要每次接收对应的两个参数,方法内需要大量的 ifelse 做逻辑覆盖,并且缺乏弹性违背开闭原则;


策略模式实现

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);
};

console.log(calculateBonus("S", 20000)); // 输出:80000
console.log(calculateBonus("A", 10000)); // 输出:30000

猜你喜欢

转载自blog.csdn.net/delete_you/article/details/129403650