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


144

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

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

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

к ES6?


Не уверен, что вы можете, есть API загрузчика модулей, или, по крайней мере, когда-то, который использовал что-то вроде System.import(module), не уверен, что это позволяет аргументы или нет, кто-то, кто знает больше о ES6, вероятно, делает?
Adeneo

Для этого есть предлагаемое решение, для которого уже есть реализации в node.js (через плагин) и в веб-пакете: 2ality.com/2017/01/import-operator.html
Мэтт Браун,

Ответы:


104

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

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

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

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

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

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

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

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

или

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

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


7
Спасибо, хотелось бы, чтобы был что-то вроде import x from 'module' use someoptions;синтаксиса
Фабрицио Джордано

1
@ Фабрицио: Если вы подумаете об этом дальше, это было бы не очень полезно. Это будет работать только в том случае, если модуль экспортирует функцию, и, вероятно, его нельзя будет разрешить, если мы назовем import (то есть import {x, y} from 'module'). Тогда какой должен быть синтаксис, если я хочу передать несколько аргументов? Или распространять массив аргументов? Это узкий вариант использования, и в основном вы пытаетесь добавить другой синтаксис для вызова функции, но у нас уже есть вызовы функций, которые позволяют нам иметь дело со всеми другими случаями.
Феликс Клинг

3
@FelixKling Я полностью с тобой согласен. Я конвертировал старое экспресс-приложение и столкнулся с var session = require('express-session'); var RedisStore = require('connect-redis')(session);вопросом, было ли решение в одну строку. Я могу полностью выжить, разделив задание RedisStore на 2 строки :)
Фабрицио Джордано

@FabrizioGiordano: Я мог бы представить что-то похожее import {default(someoptions) as x} from 'module'на ES7, если в этом действительно есть необходимость.
Берги

2
Для session/ connect-redisнапример, я себе синтаксис вроде этого: import session from 'express-session'); import RedisStore(session) from 'connect-redis'.
Джефф Хэндли

24

концепция

Вот мое решение с использованием 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в консоли

РЕДАКТИРОВАТЬ

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

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

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();
}
// ...

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


Поскольку все ваши импортированные модули являются классами, почему бы не передать параметр при создании экземпляра класса?
jasonszhao

1
@jasonszhao Самая важная вещь, которую следует отметить, заключается в том, что класс MyViewрасширяет некоторые элементы, доступные в пространстве имен платформы. Хотя это абсолютно возможно просто передать в качестве параметра классу, это также зависит от того, когда и где создается экземпляр класса; переносимость тогда затронута. На практике эти классы могут быть переданы другим средам, которые могут создавать их экземпляры по-разному (например, пользовательские компоненты React). Когда класс оказывается вне рамок фреймворка, он все равно может поддерживать доступ к фреймворку при создании экземпляра благодаря этой методологии.
Поворот

@Swivel Пожалуйста, помогите Мне нужна помощь с похожей проблемой: stackoverflow.com/questions/55214957/…
TSR

12

Основываясь на ответе @ 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!');

4

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

System.import("lib/math").then(function(m) {
  m(youroptionshere);
});

3
Но где же результат в m(youroptionshere)итоге? Я полагаю, вы могли бы написать System.import('lib/math').then(m => m(options)).then(module => { /* code using module here */})... но это не очень понятно.
Стейн де Витт

2
Ничего себе, я не могу поверить, что в E6 нет элегантного способа сделать это. Именно так я в основном пишу модули.
Роберт Москаль

3

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

import xModule from 'module';
const x = xModule('someOptions');

1
Это просто передача параметров в функцию, которую вы импортировали и вызываете. Он не передает никаких параметров модулю, из которого вы импортируете его . xModuleвводит в заблуждение здесь. То , что вы на самом деле есть это import func from 'module'; func('someOptions');.
Дан Даскалеску

1

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

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

У меня есть модуль, который запускает некоторую логику реализации сразу после загрузки. Я не люблю вызывать эту логику инициализации вне модуля (которая такая же, как call 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

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


0

Вот мой взгляд на этот вопрос на примере модуля отладки;

На странице модуля npm у вас есть это:

var debug = require ('debug') ('http')

В строке выше строка передается в импортируемый модуль для создания. Вот как бы вы сделали то же самое в ES6


import {debug as Debug} из 'debug' const debug = Debug ('http');


Надеюсь, это поможет кому-то там.


Зачем размещать ответ, который дублирует уже опубликованный ?
Дан Даскалеску

1
Виноват. Никогда не видел упомянутый пост. Просто посмотрел на вопрос и сделал удар по нему. Спасибо, что сообщили об этом.
Акинвале Фолоруншо Хабиб

Пожалуйста. Вы также можете удалить дубликат ответа, если хотите.
Дан Даскалеску
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.