Передать параметры для импорта модуля ES6

Можно ли передать параметры для импорта ES6?

Как вы это переведете:

var x = require('module')(someoptions);

to ES6?


person Fabrizio Giordano    schedule 28.04.2015    source источник
comment
Не уверен, что вы можете, есть API-интерфейс загрузчика модулей, или, по крайней мере, когда-то использовался что-то вроде System.import(module), не уверен, позволяет ли это аргументы или нет, возможно, кто-то, кто знает больше о ES6?   -  person adeneo    schedule 28.04.2015
comment
Для этого предлагается решение, для которого уже есть реализации в node.js (через плагин) и веб-пакете: 2ality.com/2017/01/import-operator.html   -  person Matt Browne    schedule 27.05.2017


Ответы (7)


Невозможно сделать это с помощью одного оператора import, он не допускает вызовов.

Таким образом, вы не будете вызывать его напрямую, но вы можете сделать то же самое, что делает commonjs с экспортом по умолчанию:

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

// main.js
import m from 'module';
var x = m(someoptions);

В качестве альтернативы, если вы используете загрузчик модулей, который поддерживает обещания monadic, вы можете выполнить что-то вроде

System.import('module').ap(someoptions).then(function(x) {
    …
});

С новым оператором import это может стать

const promise = import('module').then(m => m(someoptions));

or

const x = (await import('module'))(someoptions)

однако вам, вероятно, нужен не динамический импорт, а статический.

person Bergi    schedule 28.04.2015
comment
Спасибо, хотелось бы что-то вроде import x from 'module' use someoptions; синтаксиса - person Fabrizio Giordano; 28.04.2015
comment
@Fabrizio: Если вы подумаете об этом дальше, это будет не так уж полезно. Это будет работать только в том случае, если модуль экспортирует функцию и, вероятно, не должен быть разрешен, если мы указали импорт (например, import {x, y} from 'module'). Тогда каким должен быть синтаксис, если я хочу передать несколько аргументов? Или выкладывать массив аргументов? Это узкий вариант использования, и в основном вы пытаетесь добавить другой синтаксис для вызова функции, но у нас уже есть вызовы функций, которые позволяют нам иметь дело со всеми другими случаями. - person Felix Kling; 28.04.2015
comment
@FelixKling Я полностью с тобой согласен. Я преобразовывал старое экспресс-веб-приложение и столкнулся с var session = require('express-session'); var RedisStore = require('connect-redis')(session);. Мне просто интересно, есть ли однострочное решение. Я могу полностью выжить, разделив задание RedisStore на 2 строки :) - person Fabrizio Giordano; 28.04.2015
comment
@FabrizioGiordano: я мог бы представить что-то вроде import {default(someoptions) as x} from 'module' в ES7, если в этом действительно есть необходимость. - person Bergi; 28.04.2015
comment
Для примера session/connect-redis я представлял себе такой синтаксис: import session from 'express-session'); import RedisStore(session) from 'connect-redis'. - person Jeff Handley; 19.06.2015
comment
Я определенно вижу необходимость в этом, и я определенно пытаюсь решить эту проблему прямо сейчас. У меня есть модуль, который должен быть настоящим синглтоном в моем приложении. Проблема в том, что один из моих других модулей должен получить к нему доступ во время выполнения, поэтому к тому времени, когда мой index.js запустится, и я смогу настроить синглтон, код другого модуля уже будет поднят и запущен. Это очень расстраивает. Обертывание экспорта работает только в том случае, если вы каждый раз согласны с новым экземпляром. Но если вы хотите, чтобы один и тот же объект был сконфигурирован и разделен, вы SOL с import :-( - person RavenHursT; 24.09.2016
comment
Похоже, скоро появится официальная поддержка динамического импорта, и уже существуют реализации для узлов и веб-пакетов: 2ality.com/2017/01/import-operator.html - person Matt Browne; 27.05.2017
comment
@MattBrowne Спасибо за информацию, но это не меняет картины для статического случая. Вы не можете сделать const x = (await import(…))(options) в области модуля. (Все же?) - person Bergi; 27.05.2017
comment
@Bergi Как экспортировать несколько модулей, а не только один с одним и тем же параметром? - person TSR; 18.03.2019
comment
export default function (GreetingIntroTxt:string) { class Student { name: string; constructor(name: string) { this.name = name; } greet() { return ${GreetingIntroTxt}, + this.greeting; } } return { Student,} } Это возвращает ошибку: TS4060: возвращаемый тип экспортируемой функции имеет или использует частное имя "класс" - person TSR; 18.03.2019

Концепция

Вот мое решение с использованием ES6

Очень похоже на ответ @Bergi, это «шаблон», который я использую при создании импорта, которому нужны параметры, переданные для объявлений class. Это используется в изоморфной структуре, которую я пишу, поэтому будет работать с транспилером в браузере и в node.js (я использую Babel с Webpack):

./MyClass.js

export default (Param1, Param2) => class MyClass {
    constructor(){
        console.log( Param1 );
    }
}

./main.js

import MyClassFactory from './MyClass.js';

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

let myInstance = new MyClass();

Вышеприведенное выведет foo в консоль

ИЗМЕНИТЬ

Пример реального мира

В качестве примера из реального мира я использую это для передачи пространства имен для доступа к другим классам и экземплярам в рамках. Поскольку мы просто создаем функцию и передаем объект в качестве аргумента, мы можем использовать ее с объявлением нашего класса следующим образом:

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

Импорт немного сложнее и automagical в моем случае, учитывая, что это целая структура, но по сути это то, что происходит:

// ...
getView( viewName ){
    //...
    const ViewFactory = require(viewFileLoc);
    const View = ViewFactory(this);
    return new View();
}
// ...

Надеюсь, это поможет!

person Swivel    schedule 16.02.2016
comment
Поскольку все ваши импортированные модули являются классами, почему бы не передать параметр при создании экземпляра класса? - person user; 24.11.2016
comment
@jasonszhao Здесь важно отметить, что класс MyView расширяет некоторые элементы, доступные в пространстве имен фреймворка. Хотя вполне возможно просто передать его в качестве параметра классу, это также зависит от того, когда и где создается экземпляр класса; переносимость тогда страдает. На практике эти классы могут быть переданы другим платформам, которые могут создавать их экземпляры по-другому (например, пользовательские компоненты React). Когда класс оказывается вне области действия фреймворка, он по-прежнему может поддерживать доступ к фреймворку при создании экземпляра из-за этой методологии. - person Swivel; 24.11.2016
comment
@Swivel Пожалуйста, помогите, мне нужна помощь с аналогичной проблемой: stackoverflow.com/questions/55214957/ - person TSR; 18.03.2019

На основе ответа @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!');
person mummybot    schedule 04.04.2017
comment
машинописный текст с модулем: commonjs и esModuleInterop: true в tsconfig.js — import * as createPrompt from '../node_modules/prompt-sync'; const prompt = (createPrompt.default ?? createPrompt)();, поэтому это работает как с командами tsc, так и с ts-node - person TamusJRoyce; 28.05.2021

Я считаю, что вы можете использовать загрузчики модулей es6. http://babeljs.io/docs/learn-es6/

System.import("lib/math").then(function(m) {
  m(youroptionshere);
});
person user895715    schedule 28.04.2015
comment
Но куда попадает результат m(youroptionshere)? Я полагаю, вы могли бы написать System.import('lib/math').then(m => m(options)).then(module => { /* code using module here */})... но это не очень понятно. - person Stijn de Witt; 24.03.2016
comment
Ничего себе, я не могу поверить, что нет элегантного способа сделать это в E6. Так я в основном пишу модули. - person Robert Moskal; 21.07.2016

Вам просто нужно добавить эти 2 строки.

import xModule from 'module';
const x = xModule('someOptions');
person Mansi Teharia    schedule 25.06.2018
comment
Это просто передача параметров функции, которую вы импортировали и вызываете. Он не передает никакие параметры модулю, из которого вы его импортируете. xModule здесь вводит в заблуждение. На самом деле у вас есть import func from 'module'; func('someOptions');. - person Dan Dascalescu; 27.09.2019

Я попал в эту ветку в поисках чего-то похожего и хотел бы предложить какое-то решение, по крайней мере, для некоторых случаев (но см. примечание ниже).

Случай использования

У меня есть модуль, который запускает некоторую логику создания экземпляров сразу после загрузки. Мне не нравится вызывать эту логику инициализации вне модуля (что аналогично вызову new 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'));

Модуль А делает:

import * as S from 'service.js';     // console has now "initialized in context root"

Модуль B выполняет:

import * as S from 'service.js';     // console stays unchanged! module's script runs only once

Пока все хорошо: сервис доступен для обоих модулей, но инициализировался только один раз.

Проблема

Как заставить его работать как другой экземпляр и снова инициализировать себя в другом контексте, скажем, в модуле C?

Решение?

Вот о чем я думаю: использовать параметры запроса. В сервисе мы бы добавили следующее:

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

Модуль C сделает:

import * as S from 'service.js?context=special';

модуль будет повторно импортирован, запустится его базовая логика инициализации, и мы увидим в консоли:

initialized in context special

Примечание: я бы сам посоветовал НЕ практиковать этот подход, а оставить его в крайнем случае. Почему? Модуль, импортированный более одного раза, является скорее исключением, чем правилом, поэтому это несколько неожиданное поведение и, как таковое, может сбить с толку потребителей или даже сломать его собственные «одиночные» парадигмы, если таковые имеются.

person GullerYA    schedule 24.06.2019

person    schedule
comment
Зачем публиковать ответ, который дублирует уже опубликованный ответ? - person Dan Dascalescu; 30.01.2019
comment
Виноват. Никогда не видел упомянутого поста. Просто посмотрел на вопрос и нанес удар по нему. Спасибо, что довели это до моего сведения. - person Akinwale Folorunsho Habib; 14.02.2019
comment
Пожалуйста. Вы также можете удалить повторяющийся ответ, если хотите. - person Dan Dascalescu; 27.09.2019