ES7装饰器详解

本文将从以下几个角度解析装饰器:

1. 装饰器模式;
2. 装饰器的基本概念;
3. 装饰器的类型;

一、什么是装饰器模式:

要想正确理解设计模式,首先必须明确它是为了解决什么问题而提出来的。

那装饰器模式到底是为了解决什么问题呢?在我们的开发过程中我们会为了一些通用功能在多个不同的组件、接口或者类中使用,这个时候我们这些功能写到每个组件、接口或者类中,但是这样非常不利于维护。

装饰器就是为了解决在不修改原本组件、接口或者类的时候为其添加额外的功能。

从本质上看装饰器模式是一个包装模式((Wrapper Pattern),它是通过封装其他对象达到设计的目的的。

react的高阶组件本质也是装饰器模式,以后会有一篇文章会专门详解react的高阶组件。

理解了装饰器的能解决了什么问题,那我们一遍在什么情况下考虑使用装饰器模式呢?我的理解是:

  • 需要扩展一个类,为这个类附加一个方法或者属性的时候;
  • 需要修改一个类的功能,或者重构这个类中的某个方法;

二、装饰器的基本概念:

上面我们解释了什么是装饰器模式,下面我们将要ES7的装饰器的一些基本概念:如何定义装饰器、装饰器执行时机、装饰器类型。

1、如何定义装饰器

装饰器本质是一个函数,可以分为带参数和不带参数(也叫装饰器工厂),装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。

@Test()
class Hello {}

function Test(target:any) {
    console.log("I am decorator.")
}

2、装饰器执行时机

修饰器对类的行为的改变,是代码编译时发生的(不是TypeScript编译,而是js在执行机中编译阶段),而不是在运行时。这意味着,修饰器能在编译阶段运行代码。也就是说,修饰器本质就是编译时执行的函数

3、装饰器的类型

类装饰器、属性装饰器、方法装饰器、参数装饰器

三、装饰器类型:

  • 类修饰器

类装饰器一般主要应用于类构造函数,可以监视、修改、替换类的定义,装饰器用来装饰类的时候。装饰器函数的第一个参数,就是所要装饰的目标类本身。

a、添加静态属性或方法

@Test()
class Hello {}

function Test(target) {
   target.a = 1;
}

let o = new Hello();

console.log(o.a) ==>1

b、添加实例属性或方法

@Test()
class Hello {}

function Test(target) {
   target.prototype.a = 1;
   target.prototype.f = function(){
       console.log("新增加方法")
   };

}

let o = new Hello();
o.f() ==>"新增加方法"
console.log(o.a) ==>1

c、装饰器工厂(函数柯里化)

很多文章说装饰器工厂是闭包,其实不准确,关于高阶函数、闭包、函数柯里化可以参考:
理解运用JS的闭包、高阶函数、柯里化

@Test('hello')
class Hello {}

function Test(str) {
   return function(){
        target.prototype.a = str;
        target.prototype.f = function(){
            console.log(str)
        };
   }

}

let o = new Hello();
o.f() ==>"hello"
console.log(o.a) ==>"hello"

d、重载构造函数

@Test('hello')
class Hello {
    constructor(){
        this.a= 1
    }
    f(){
         console.log('我是原始方法',this.a)
    }

}

function Test(target) {
  return class extends target{
      f(){
         console.log('我是装饰器方法',this.a)
    }
  }

}

let o = new Hello();
o.f() ==>"我是装饰器方法",1
  • 方法装饰器

它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰会在运行时传入下列3个参数:

  1. target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. key: 成员的名字。
  3. descriptor:成员的属性描述符。
descriptor:
// {
//   value: specifiedFunction,
//   enumerable: false,
//   configurable: true,
//   writable: true
// };

方法装饰器最后必须返回descriptor

function nameDecorator(target, key, descriptor) {
    descriptor.value = () => {
        return 'jake';
    }
    return descriptor;
}

class Person {
    constructor() {
        this.name = 'jake'
    }
    @nameDecorator
    getName() {
        return this.name;
    }
}

let p1 = new Person();
console.log(p1.getName())



另外一个经典例子

class Math {
  @log
  add(a, b) {
    return a + b;
  }
}

function log(target, name, descriptor) {
  var oldValue = descriptor.value;

  descriptor.value = function(...list) {
    console.log(list);
    console.log(`Calling ${name} with`, ...list);
    return oldValue.call(this, ...list);
  };

  return descriptor;
}

const math = new Math();

// passed parameters should get logged now
let result = math.add(2, 4);

console.log(result)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348