JavaScript 动态导入类模块并获取类名

8
这个问题涉及到Chrome浏览器。
我正在尝试动态导入一个定义为类的JavaScript模块。
// data-table.js
export class DataTable extends HTMLElement{
    constructor() {
        super();
    }
    static get tagName() {
        return 'data-table';
    }
} 

我想知道如何获取目标代码中已导入类的名称。 以下是我的目标代码,但它无法工作。
// router.js
...//some code
if(route === matched){
   // dynamically import the component
   import(route.component) 
    .then( module => {
      // anyway to get classname DataTable here??
    
 })
 };
...//rest of the code

以下是一个显而易见的实现,它能够工作(因为我硬编码了模块类名)

// router.js
...//some code
if(route === matched){
   // dynamically import the component
   import("components/data-table.js") 
    .then( {DataTable} => {
     cost t = DataTable.tagName;
     // code to handle module stuff
 })
 };
...//rest of the code
 

这里有一个类似的问题(链接),但没有给出可行的答案,不过那个问题是关于Webpack的,而我是直接在浏览器中尝试。 为什么我要获取类名? 因为这使得我的代码更简单。


你为什么要尝试导入一个你甚至不知道的类?你为什么要给这个类命名呢? - Bergi
这是一个路由器实现的努力。当匹配到一个路由时,我想要导入相应的类并运行它。由于整个匹配部分是动态的,因此在路由器中需要哪个类事先是未知的。 - Ali Masood
用户传递给您的路由器的路由定义应包含要使用的类名。或者,如果您只有模块列表,请确保每个模块都实现相同的接口 - 即默认导出。 - Bergi
4个回答

7
使用默认导出和动态导入时,您需要解构并重命名返回对象中的"default"键。
import(route.component)
    .then(({ default: DataTable }) => { 
        console.log(DataTable.tagName);
    });

我遇到了同样的问题,但我在Node中使用了async / await:

const { default: myClass } = await import('/path/to/class.js');

这使我能够访问myClass对象的静态属性方法。


如果该模块使用默认导出,则这将是正确的答案。但它没有这样做。 - coagmano
1
在我看来,如果一个文件中只有一个导出,那它应该是默认导出。无论如何,我希望我的回答能够帮助到任何遇到我曾经遇到的同样问题的人。我花了一些时间才想出正确地解构它的方法。 - Jeff Kilbride
1
非常公正,这确实有助于通过搜索找到问题的其他人,所以我非常迟地给了你加1,这本该是第一次的。 - coagmano

4

我不认为这通常是一个好主意(参见@Steven's Answer),但是回答这个问题:

import("foo").then(module => {
    let name = Object.keys(module)[0];
});

这并不是最佳的做法,但仍然可以解决问题。
这仅适用于以export class ...形式进行单个导出的情况。

2
你已经在解构{DataTable}了(你的语法有误,应该是({DataTable})),这说明它是模块中的一个关键字,相当于module.DataTablemodule['DataTable']。因此你已经拥有了它。如果你在开发时真正知道名称DataTable,那么你已经有了一个字符串。
但是,假设你不知道名称,或者它以公共名称出现,例如export const Component = DataTable,这时你可以通过一个一致的方式访问它:module.Component
在任何一种情况下,只要你拥有类对象,它就是一个函数,具有属性.name,所以你总可以这样做:DataTable.name === 'DataTable'
但根据我的专业意见,像这样进行元编程来节省一点工作会导致脆弱的代码,在某些时候几乎总是出乎意料地出现错误。

-1

我在nodeJS中遇到了相同的问题。我有一个包含Equalizer类(不是默认的)和只有static方法的JavaScript文件。我加载了partial pages。当加载一个partial page时,我会把它放在下面:

  import("/assets/js/equalizer.js").then(module => module.Equalizer.init());

现在我可以动态加载javascript,并在加载后执行其中的函数。因此,在网站加载时无需加载所有JavaScript文件。enter code here


你在代码中硬编码了“Equalizer”。问题明确说明他们有一个工作解决方案,其中硬编码了导出名称。问题的重点是他们不想这样做。 - Quentin
好的,我重新阅读了问题,现在明白了问题所在。问题在于Javascript和像C#这样的语言之间的区别。在C#中,您不使用模块,而是默认使用类。因此,当您想要使用某些内容时,需要导入它。在这种情况下,该内容是一个类。在C#中,一个文件中可以有很多类。当您使用Javascript导入文件时,会得到模块对象。从这个对象中,您可以定义要从该模块中使用的内容。在我的情况下,它是一个“均衡器”,在播放音乐时显示均衡器。Javascript正在转变为更像C#的语言风格。 - Herman Van Der Blom
“Hardcoded”这个词是不正确的。使用新的ES6编程风格,您不再使用JavaScript文件。你将所有东西打包到类中并导入它们。因此,当您将编程样式更改为ES6时,上述问题会自动得到解决。 - Herman Van Der Blom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接