代码之家  ›  专栏  ›  技术社区  ›  Kris Oye

如何获取JavaScript类构造函数的描述符?

  •  0
  • Kris Oye  · 技术社区  · 11 月前

    我能得到JS类的实际构造函数的描述符吗?我正在为Express编写自己的小包装,尝试按程序生成路线和内容(我相信还有很多其他库可以做到这一点,但这是一种学习体验)。

    如果我迭代类原型的函数描述符,我可以将“value”属性转换为表示单个方法的字符串。如果我对“constructor”的描述符调用getString(),我会得到整个类。我只想要建造者的尸体。我可以添加更多的解析逻辑,但必须有一种方法来做到这一点。

    这是一个简单的控制器:

    const
        BaseController = require('../src/baseController');
    
    /**
     * Handle requests for the home page
     */
    class HomeController extends BaseController {
        /**
         * @param settings Controller settings
         * @param vault Injected vault client
         */
        constructor(settings, vault) {
            super(settings);
            this.vault = vault;
        }
    
        /**
         * Serve the landing page
         * @returns 
         */
        async get() {
            await this.renderAsync({ pageTitle: 'Pechanga Demo' });
        }
    }
    
    module.exports = HomeController;
    

    以下是目前“get”返回的内容:

    Object.getOwnPropertyDescriptor(controllerType.prototype, 'get').value.toString()
    
    async get() {
       await this.renderAsync('index', { pageTitle: 'Pechanga Demo' });
    }
    

    但是,获取“constructor”的描述符会返回整个类体:

    Object.getOwnPropertyDescriptor(controllerType.prototype, 'constructor').value.toString()
    

    我真正想要的只是:

        constructor(settings, vault) {
            super(settings);
            this.vault = vault;
        }
    

    这可以在不解析整个类体的情况下实现吗?

    1 回复  |  直到 11 月前
        1
  •  1
  •   Johannes H.    11 月前

    这里的问题是Javascript没有类的概念,也没有构造函数。是的,在最近的版本中,它可能有一个类和一个构造函数关键字,但在幕后,它仍然是一个基于原型的语言。这些关键字只是句法糖,这就是导致问题的原因,因为它让你假设 .prototype.constructor 跟thwe有点关系 constructor() 类中的语法。然而,事实并非如此。

    让我们来看看这个最小的例子:

    class Bar {
        constructur (value) {
            this.property1 = value;
        }
    }
    
    class Foo extends Bar {
        constructor (value1, value2) {
            super(value1);
            this.property2 = value2;
        }
    }
    

    在传统的纯Javascript中,您可以这样设置:

    function Bar (value) {
        this.property1=value;
    }
    
    function Foo (value1, value2) {
        Bar.call(this,value1);
        this.property2 = value2;
    }
    Object.setPrototypeOf(Foo.prototype, Bar.prototype);
    

    这反过来又是句法糖

    var Bar = function Bar (value) {
        this.property1=value;
    }
    var Foo = function Foo (value1, value2) {
        Bar.call(this,value1);
        this.property2 = value2;
    }
    Object.setPrototypeOf(Foo.prototype, Bar.prototype);
    

    现在,如果我们看看 Foo ,这显然是一个函数,我们可以清楚地看到,当我们显式地给变量赋值时,它就是一个函数。作为所有功能 toString() 它的方法将返回它的源代码(除非它是原生的)。

    与Javascript中的所有函数一样,Foo也有一个名为 .prototype 它只存在于建立适当的 [[Prototype]] 对于使用创建的对象 new Foo 该对象随后具有一个名为的属性 constructor 它指向了为其创建的函数,即 Foo 本身。 所以 Foo.prototype.constructor.toString() Foo.toString() 并将打印以下内容的源代码 Foo -正如你所料。

    你可以在这里清楚地看到: .constructor 函数的属性 原型 财产与 构造者() 类中的语法。它完全独立存在。

    现在,如果你使用语法糖,让你认为Javascript有类 toString() 方法 Foo.prototype.constructor 将与以前完全一样:它将打印定义的源代码 Foo . 也就是说,在“我们使用了句法糖”的情况下, class Foo extends Bar {constructor (value1, value2) {super(value1); this.property2 = value2;}} .

    所以,你看到的是“按预期工作”。

    如果你想要的内容 构造者() 单独使用时,您需要以传统方式设置它而不使用类符号,或者需要解析类的源代码并提取相关部分。没有函数可以为您完成此操作,也没有与内容相对应的对象 构造者() ,因为它实际上并不存在于编译后的代码中。