装饰器模式和转发,call/apply

装饰器(decorator)

一个特殊的函数,它接受另一个函数并改变它的行为,它返回缓存包装器。

let worker = {
  slow(min, max) {
    alert(`Called with ${min},${max}`);
    return min + max;
  }
};

function cachingDecorator(func, hash) {
  let cache = new Map();
  return function() {
    let key = hash(arguments); // 利用哈希函数缓存多参数
    if (cache.has(key)) {
      return cache.get(key);
    }

   let result = func.call(this, ...arguments); 
   
   // 适用于对象方法,使用 “func.call” 设定上下文,普通函数不用。
   
   //当我们期望可迭代对象时,使用 call,当我们期望类数组对象/真正的数组时,使用 apply!
   
   cache.set(key, result);
    return result;
  };
}

// 哈希函数
function hash(args) {
  return args[0] + ',' + args[1];
}

worker.slow = cachingDecorator(worker.slow, hash);

alert( worker.slow(3, 5) ); // works
alert( "Again " + worker.slow(3, 5) ); // same (cached)
  1. 呼叫转移(call forwarding): 将所有参数连同上下文一起传递给另一个函数。
    通常是使用 apply 完成的:
let wrapper = function() {
  return original.apply(this, arguments);
};
  1. 方法借用(method borrowing):使哈希函数适用于任何数量的参数。 从一个对象中获取一个方法,并在另一个对象的上下文中“调用”它。采用数组方法并将它们应用于参数 arguments 是很常见的。另一种方法是使用 Rest 参数对象,该对象是一个真正的数组。
function hash() {
  alert( [].join.call(arguments) ); // 1,2
}

hash(1, 2);

//我们从常规数组 [].join 中获取(借用)join 方法,
  并使用 [].join.call 在 arguments 的上下文中运行它。

原生方法 arr.join(glue) 的内部算法:

(1)让 glue 成为第一个参数,如果没有参数,则使用逗号 “,”。
(2)让 result 为空字符串。
(3)将 this[0] 附加到 result。
(4)附加 glue 和 this[1]。
(5)附加 glue 和 this[2]。
(6)……以此类推,直到 this.length 项目被粘在一起。
(7)返回 result。

因此,从技术上讲,它需要 this 并将 this[0],this[1] ……等 join 在一起。它的编写方式是故意允许任何类数组的 this 的(不是巧合,很多方法都遵循这种做法)。这就是为什么它也可以和 this=arguments 一起使用。

  1. 装饰器和函数属性:装饰后的函数将不再提供原始函数的属性。
    一些包装器可能会提供自己的属性,eg.装饰器会计算一个函数被调用了多少次以及花费了多少时间,并通过包装器属性公开(expose)这些信息。
    存在一种创建装饰器的方法,该装饰器可保留对函数属性的访问权限,但这需要使用特殊的 Proxy 对象来包装函数。我们将在后面的 Proxy 和 Reflect 中学习它。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值