JS设计模式之装饰者模式

文章目录
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 简单的例子
    2. 2.2. ES7的装饰器
    3. 2.3. 和代理模式的对比

前言

本文759字,阅读大约需要5分钟。

总括: 在Javascript中实现23种经典设计模式的装饰者模式。

  • 公众号:「前端进阶学习」,回复「666」,获取一揽子前端技术书籍

与有肝胆人共事,从无字句处读书

正文

装饰者模式(Decorator pattern): 在不改变原对象的基础上,通过对其进行包装拓展使原对象能满足更为复杂的需求

简单的例子

在Javascript中这是一种比较常见的设计模式,主要的使用场景是针对某个函数或是对象增加某些特性或是功能。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
var a = function() {
console.log(1);
// 其它代码
}
var _a = a;
a = function() {
_a();
console.log(2);
// 其它代码
}
a();
// 打印 1
// 打印 2

比较现实点的实现比如window.onload函数:

1
2
3
4
5
6
7
8
9
10
window.onload = function() {
console.log(1);
}
var _onload = window.onload;
window.onload = function() {
_onload();
console.log(2);
}
// 打印 1
// 打印 2

为了避免覆盖其它同事写的onload函数,往往采用如上的实现,但这样的实现有个弊端在于如果装饰链很长会导致诸如_onload这样的中间变量非常多;另外还存在this丢失的问题,直接调用_onload会导致内部this指向window

1
2
3
4
5
6
var _getElementById = document.getElementById;
document.getElementById = function(id) {
console.log(1);
return _getElementById(id);
}
var div = document.getElementById('test');

如上代码会报错:

1
Uncaught TypeError: Illegal invocation

原因就在于此时_getElementById函数this指向window而不是document。解决方案也很简单,可以把this`手动传进去。

1
2
3
4
5
6
var _getElementById = document.getElementById;
document.getElementById = function(id) {
console.log(1);
return _getElementById.call(document, id);
}
var div = document.getElementById('test');

上面的代码就正常了。

ES7的装饰器

装饰者模式的好用和广泛使用使得ES7中直接引入了这个模式的实现。其实它是个语法糖,支持对类和方法的装饰,实际的应用代码类似于:

1
2
3
4
5
6
7
@decorator
class A {}

// 等同于

class A {}
A = decorator(A) || A;

和代理模式的对比

代理模式和装饰者模式都保留了原对象或是方法的引用,然后对原对象做处理。区别在于他们两者的目的。

  • 代理模式的目的是为了提供一个替代者,当不能直接访问原对象或是不符合需要的时候,为原对象提供一个替代者,在访问真正的原对象之前也可以做一些额外的事情;
  • 装饰者模式的目的是为了添加一种行为,为原对象添加一种特性。

以上。


能力有限,水平一般,欢迎勘误,不胜感激。

转载请获本人授权,并注明作者和出处。

订阅更多文章可关注公众号「前端进阶学习」,回复「666」,获取一揽子前端技术书籍

前端进阶学习

如果您觉得我的文章对您有用,请随意打赏。

您的支持将鼓励我继续创作!

人过留名,雁过留声
听听你的声音

回复 Username 留言: content x