• home > webfront > ECMAS > typescript >

    typescript装饰器的ES6实现

    Author:zhoulujun Date:

    JavaScript 装饰器支持仍处于提案阶段。但是,装饰器的概念对 JavaScript 来说并不新鲜,因为高阶函数是函数装饰器的另一种形式。

    在《Typescript装饰器Decorators浅析》中:

    元编程(MetaProgramming)

    元编程是用代码在编译期或运行期生成/改变代码。

    Meta- 这个前缀在希腊语中的本意是「在…后,越过…的」,类似于拉丁语的 post-,大陆将 meta- 这个前缀译为「元」并不恰当。台湾译为「后设」,稍微好一点点,但仍旧无法望文生义。也许「自相关」是个不错的选择,「自相关数据」、「自相关语言」、「自相关编程」——但是好像又太罗嗦了。

    元编程通常有两种方式起作用。一种方式是通过应用程序接口(API)来暴露运行时引擎的内部信息。另一种方法是动态执行包含编程命令的字符串。因此,“程序能编写程序”。虽然两种方法都能用,但大多数方法主要靠其中一种。

    ECMAScript 2015 开始,JavaScript 获得了 Proxy 和 Reflect 对象的支持,允许你拦截并定义基本语言操作的自定义行为(例如,属性查找,赋值,枚举,函数调用等)。借助这两个对象,你可以在 JavaScript 元级别进行编程。

    TypeScript的装饰器,是个非常好的选择

    Reflect(反射)是 ES6 为了操作对象而提供的新 API,可用于实现js的元编程。但在ECMAScript Reflect 规范中,缺失了Reflect Metadata。Reflect Metadata主要可以用于定义和操作元数据信息。

    如果要使用这个功能,可以借助 reflect-metadata 这个库实现。但是装饰器 还是不行。

    尽管装饰器在 TypeScript 和 Python 等语言中被广泛使用,但是 JavaScript 装饰器的支持仍处于第 2 阶段提案中(stage 2 proposal)。

    JavaScript如何实现装饰器?

    JavaScript 装饰器支持仍处于提案阶段。但是,装饰器的概念对 JavaScript 来说并不新鲜,因为高阶函数是函数装饰器的另一种形式

    从java注解漫谈到typescript装饰器——注解与装饰器》一文中,typescript装饰器有:

    装饰器类型

    装饰器的类型有:类装饰器、访问器装饰器、属性装饰器、方法装饰器、参数装饰器,但是没有函数装饰器(function)。

    在 JavaScript 中分出 3 种类型的装饰器:

    • 函数装饰器——用函数来包装函数。

    • 类装饰器—— 一次应用于整个类。

    • 类成员装饰器——应用于类的成员

    目前,不能在浏览器或 Node.js 环境中运行类装饰器,因为它们需要转译器支持。但是,如果使用函数式装饰器,则可以在任何地方运行它们

    function multiply(x, y) {
      console.log('Total : ' + (x*y));
    }
    
    function logDecorator(logger) {
      return function (message) {
        const result = logger.apply(this, arguments);
        console.log("Logged at:", new Date().toLocaleString());
        return result;
      }
    }
    
    const wrapperFunction = logDecorator(multiply);
    wrapperFunction(10,10)

    但是如果要实现类装饰器呢?

    // 高阶函数,用来模拟类装饰器
    function classDecorator(targetClass) {
        // 获取原始构造函数
        const originalConstructor = targetClass;
    
        // 创建一个新的构造函数,用来包装原始构造函数
        function newConstructor(...args) {
            console.log('Applying class decorator...');
            
            // 创建原始构造函数的实例
            const instance = new originalConstructor(...args);
    
            // 返回实例
            return instance;
        }
    
        // 拷贝原始构造函数的原型,以保证原型链的完整
        newConstructor.prototype = Object.create(originalConstructor.prototype);
        // 修正原型的构造器指向
        newConstructor.prototype.constructor = newConstructor;
    
        return newConstructor; // 返回新的构造函数
    }
    
    // 使用装饰器的方式模拟调用
    const DecoratedClass = classDecorator(
        class {
            constructor(name) {
                this.name = name;
            }
    
            greet() {
                return `Hello, ${this.name}!`;
            }
        }
    );
    
    // 使用新的构造函数创建对象
    const instance = new DecoratedClass('Alice');
    console.log(instance.greet()); // 输出:Hello, Alice!

    在上述代码中,classDecorator 函数接受一个构造函数作为参数,并返回一个新的构造函数。在新的构造函数内部,我们可以在实例化原始构造函数的实例之前或之后添加自定义的行为,这就像在 TypeScript 中使用装饰器一样。最重要的是保持原型链的完整性,我们需要确保新构造函数的原型链与原始构造函数的原型链相同。




    转载本站文章《typescript装饰器的ES6实现》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/typescript/2022_0616_9053.html