将选项传递给ES6模块导入

Fab*_*ano 132 javascript module ecmascript-6 es6-modules

是否可以将选项传递给ES6导入?

你怎么翻译这个:

var x = require('module')(someoptions);
Run Code Online (Sandbox Code Playgroud)

到ES6?

Ber*_*rgi 97

没有办法用单个import语句执行此操作,它不允许调用.

所以你不会直接调用它,但你基本上可以做与commonjs默认导出相同的操作:

// module.js
export default function(options) {
    return {
        // actual module
    }
}

// main.js
import m from 'module';
var x = m(someoptions);
Run Code Online (Sandbox Code Playgroud)

或者,如果您使用支持monadic promises 的模块加载器,您可能可以执行类似的操作

System.import('module').ap(someoptions).then(function(x) {
    …
});
Run Code Online (Sandbox Code Playgroud)

随着新的import运营商,它可能会成为

const promise = import('module').then(m => m(someoptions));
Run Code Online (Sandbox Code Playgroud)

要么

const x = (await import('module'))(someoptions)
Run Code Online (Sandbox Code Playgroud)

但是你可能不希望动态导入而是静态导入.

  • 谢谢,我希望有一些类似`import x from'module'的东西使用someoptions;`有点语法 (6认同)
  • @FelixKling我完全同意你的看法.我正在转换一个旧的快速webapp,我遇到`var session = require('express-session'); var RedisStore = require('connect-redis')(session);`我只是想知道是否有一行解决方案.我完全可以通过拆分RedisStore分配2行:) (3认同)
  • 对于`session` /`connect-redis`的例子,我一直想象这样的语法:`import session from'express-session'); 从'connect-redis'`导入RedisStore(session). (2认同)

Swi*_*vel 21

概念

这是我使用ES6的解决方案

非常符合@ Bergi的响应,这是我在创建需要为class声明传递参数的导入时使用的"模板" .这是用在同构框架,我在写,所以会在浏览器和node.js中(我用的是transpiler工作BabelWebpack):

./MyClass.js

export default (Param1, Param2) => class MyClass {
    constructor(){
        console.log( Param1 );
    }
}
Run Code Online (Sandbox Code Playgroud)

./main.js

import MyClassFactory from './MyClass.js';

let MyClass = MyClassFactory('foo', 'bar');

let myInstance = new MyClass();
Run Code Online (Sandbox Code Playgroud)

以上将foo在控制台中输出

编辑

真实世界的例子

对于一个真实世界的例子,我使用它传递一个名称空间来访问框架内的其他类和实例.因为我们只是创建一个函数并将对象作为参数传递,所以我们可以将它与我们的类声明一起使用:

export default (UIFramework) => class MyView extends UIFramework.Type.View {
    getModels() {
        // ...
        UIFramework.Models.getModelsForView( this._models );
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

输入有点复杂,automagical在我的情况下,它是一个完整的框架,但实际上这是正在发生的事情:

// ...
getView( viewName ){
    //...
    const ViewFactory = require(viewFileLoc);
    const View = ViewFactory(this);
    return new View();
}
// ...
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助!


mum*_*bot 9

基于@ Bergi 使用es6 使用调试模块答案如下

// original
var debug = require('debug')('http');

// ES6
import * as Debug from 'debug';
const debug = Debug('http');

// Use in your code as normal
debug('Hello World!');
Run Code Online (Sandbox Code Playgroud)

  • tsconfig.js 中带有 "module": "commonjs" 和 "esModuleInterop": true 的打字稿 - `import * as createPrompt from '../node_modules/prompt-sync'; const prompt = (createPrompt.default ?? createPrompt)();` 所以这适用于 tsc 和 ts-node 命令 (2认同)

Gul*_*rYA 7

我已经登陆这个线程寻找一些类似的解决方案,并想提出一种解决方案,至少对于某些情况(但请参阅下面的备注)。

使用案例

我有一个模块,它在加载后立即运行一些实例化逻辑。我不喜欢在模块外部调用此 init 逻辑(与 callnew SomeClass(p1, p2)new ((p1, p2) => class SomeClass { ... p1 ... p2 ... })等相同)。

我确实喜欢这个初始化逻辑将运行一次,有点像单一的实例化流程,每个特定的参数化上下文运行一次。

例子

service.js其基本范围包括:

let context = null;                  // meanwhile i'm just leaving this as is
console.log('initialized in context ' + (context ? context : 'root'));
Run Code Online (Sandbox Code Playgroud)

模块 A 的作用是:

import * as S from 'service.js';     // console has now "initialized in context root"
Run Code Online (Sandbox Code Playgroud)

模块 B 执行以下操作:

import * as S from 'service.js';     // console stays unchanged! module's script runs only once
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利:服务可用于两个模块,但仅初始化一次。

问题

如何让它作为另一个实例运行并在另一个上下文中再次初始化自身,比如在模块 C 中?

解决方案?

这就是我正在考虑的:使用查询参数。在服务中我们添加以下内容:

let context = new URL(import.meta.url).searchParams.get('context');

模块 C 会执行以下操作:

import * as S from 'service.js?context=special';
Run Code Online (Sandbox Code Playgroud)

该模块将被重新导入,它的基本初始化逻辑将运行,我们将在控制台中看到:

initialized in context special

备注:我自己建议不要过多练习这种方法,而是将其作为最后的手段。为什么?多次导入的模块更多的是例外而不是规则,因此这在某种程度上是意外的行为,因此可能会让消费者感到困惑,甚至打破它自己的“单例”范例(如果有的话)。