使用 TypeScript 自定义装饰器给类的属性增添监听器 Listener

官网链接

语法

type PropertyDecorator =
  (target: Object, propertyKey: string | symbol) => void;

target:直接写在类的属性上?

看个例子:

function capitalizeFirstLetter(str: string) {
  return str.charAt(0).toUpperCase() + str.slice(1);
}

function observable(target: any, key: string): any {
  // prop -> onPropChange
  const targetKey = "on" + capitalizeFirstLetter(key) + "Change";

  target[targetKey] =
    function (fn: (prev: any, next: any) => void) {
      let prev = this[key];
      Reflect.defineProperty(this, key, {
        set(next) {
          fn(prev, next);
          prev = next;
        }
      })
    };
}

class C {
  @observable
  foo = -1;

  @observable
  bar = "bar";
}

const c = new C();

c.onFooChange((prev, next) => console.log(`prev: ${prev}, next: ${next}`))
c.onBarChange((prev, next) => console.log(`prev: ${prev}, next: ${next}`))

c.foo = 100; // -> prev: -1, next: 100
c.foo = -3.14; // -> prev: 100, next: -3.14
c.bar = "baz"; // -> prev: bar, next: baz
c.bar = "sing"; // -> prev: baz, next: sing

编译通不过:

一种解决办法是,添加下图这种 dummy 方法,这种方法不推荐,因为缺乏灵活性:

另一种方法较通用,即为类添加通用的所谓的 index signature:

语法如下:

意思是类 C 可以拥有任意的属性,且属性名称为 string

运行时,target 的类型为类 C 的构造函数:

key 为属性名:

在下图第 15 行代码,直接给 C 的构造函数注入一个新的 on 监听函数:

这个监听函数的函数体,直到代码44行 onXXX 被调用时才会被执行:

给 C 对象实例的 foo 属性使用 Reflect.defineProperty API 设置一个 set 方法。

这样,每次该实例的 foo 属性被修改时,就触发其 set 函数:

在 set 函数实现体内,首先调用应用开发人员传入的 回调函数 fn,然后将 this[key] 设置为新的值 next.

运行时,c.foo = 100, 会导致 Reflect.defineProperty 注册在 foo 属性的 set 方法被触发:

在 set 函数里,我们再也不能访问到 C 实例的 foo 或者 bar 属性,但是通过闭包,能访问到其修改之前的原始值:

(0)

相关推荐

  • (25条消息) Rust 中的属性

    属性是什么 属性(Attribute)是一种通用的自由格式的元数据,Rust 中的属性以ECMA-335中的为模型,其语法则来自ECMA-334(C#). 属性的用途 属性只能应用于 Rust 中的项 ...

  • 科技·Kotlin从入门到精通,类和对象

    类和对象是两种以计算机为载体的计算机语言的合称.对象是对客观事物的抽象,类是对对象的抽象.类是一种抽象的数据类型.它们的关系是,对象是类的实例,类是对象的模板.类定义Kotlin类可以包含:构造函数和 ...

  • Java基础之:List——LinkedList

    LinkedList简单介绍 LinkedList实现了双向链表(数据结构)和双端队列特点. 实现了List接口,可以添加任意元素(即可以重复和null),线程不安全. LinkedList底层实现分 ...

  • getter和setter以及defineProperty的用法

    getter 和 setter 和 defineProperty getter:将对象属性绑定到查询该属性时将被调用的函数 说人话就是,当你调用一个getter属性时会调用定义好的get函数,这个函数 ...

  • 使用 TypeScript 自定义装饰器给类的方法增添监听器 Listener

    方法装饰器 语法 type MethodDecorator = <T>( target: Object, propertyKey: string | symbol, descriptor: ...

  • TypeScript 类装饰器的一个例子和使用单步调试搞清楚其运行原理

    官方文档 类装饰器的定义如下: type ClassDecorator = <TFunction extends Function> (target: TFunction) => T ...

  • TypeScript reflect-metadata 结合方法装饰器实现的一个自定义语法检查的例子

    reflect-metadata 例子: import 'reflect-metadata'; function validate( target: Object, key: string, desc ...

  • Python 中的函数装饰器和闭包

    函数装饰器可以被用于增强方法的某些行为,如果想自己实现装饰器,则必须了解闭包的概念. 装饰器的基本概念 装饰器是一个可调用对象,它的参数是另一个函数,称为被装饰函数.装饰器可以修改这个函数再将其返回, ...

  • Selenium2+python自动化55-unittest之装饰器(@classmethod)

    前言 前面讲到unittest里面setUp可以在每次执行用例前执行,这样有效的减少了代码量,但是有个弊端,比如打开浏览器操作,每次执行用例时候都会重新打开,这样就会浪费很多时间. 于是就想是不是可以 ...

  • 设计模式-装饰器模式

    装饰器模式 定义 装饰器模式也叫包装模式 在不改变原有对象的基础上,把功能附加到对象上,提供了比继承更有弹性的替代方案 能够扩展原有对象的功能 属于结构型模式 生活中的例子 买煎饼 我们煎饼可以加鸡蛋 ...

  • PHP设计模式之装饰器模式

    PHP设计模式之装饰器模式 工厂模式告一段落,我们来研究其他一些模式.不知道各位大佬有没有尝试过女装?据说女装大佬程序员很多哟.其实,今天的装饰器模式就和化妆这件事很像.相信如果有程序媛MM在的话,马 ...

  • [PHP小课堂]PHP设计模式之装饰器模式

    [PHP小课堂]PHP设计模式之装饰器模式 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[DarkMatterZyCoder/149844827]免费得PHP.项目管理学习资料

  • 3年工作必备 装饰器模式

    回复"000"获取大量电子书 大家好,我是老田,从今天开始,本公众号每周给大家送福利,送什么呢?肯定是技术书啦,没那么多花里胡哨的,参与方式见文末. 好啦,进入我们的主题,今天我给 ...