动态ES6模块范围

时间:2015-05-24 17:34:00

标签: javascript ecmascript-6 babeljs traceur es6-module-loader

所有当前模块加载器(如AMD,CommonJS,SystemJS)使用变量定义将外部对象加载到当前模块范围

像:  

var something = require('something');

或:  

define('module',['something'],function(something){});

如果您不知道需要从外部模块导入什么,或者只需要导入所有内容,这就成了问题,因为无法在运行时定义变量。

我猜这是ES6翻译不使用

的主要原因  
import * from 'something';

语法,它们不包含在ES6规范中。

所以说动态模块范围我的意思是模块变量可以定义/加载运行时,这将允许将ES6语法扩展为某种东西 喜欢:  

import * from 'something';
import Something.* from 'something';
import /regexp/ from 'something';

在我看来,这是定义导入的更佳方式,而不是列出所有名称,如:
 

import {
    ONE,
    TWO,
    ...
} from 'something';

现在我真正的问题:

  

为什么不使用with来实现这一目标?

以下是从ES6到ES5的简单示例翻译,可以解决问题:

file:modules / module-1.js

var localVar = 'VALUE';
function localFun(a,b){
    return a +' and '+ b;
}
export {
    localVar as module1Var
    localFun as module1Fun
}

于:

(function(){
    // define module named 'modules/module-1' 
    // and return related scope object 
    // containing 'execute_module' function predefined 
    with (define_module('modules/module-1')) {
        // will register actual module execution 
        // which will be called after all imports 
        // initialized 
        execute_module(function(){
            var localVar = 'VALUE';
            function localFun(a,b){
                return a +' and '+ b;
            }
            // returns value as current module exports 
            return {
                module1Var : localVar,
                module1Fun : localFun
                // ...
            };
        });
    }
})();

file:modules / module-1.js

import * from 'modules/module-1.js';

console.info(module1Fun(module1Var)); //prints: VALUE and VALUE

于:

(function(){
    // define module named 'modules/module-2' 
    // after execute is called loader will do 
    // all imports and bind exports from modules 
    // to current module scope and then invoke callback
    // after which imported variables will appear in with scope
    // and will be visible in callback scope. 
    with (define_module('modules/module-2',{
        'modules/module-1' : '*',
        // also can filter exports by regexp
        'modules/other'    : /.*/
    })) {
        execute_module(function(){
            console.info(module1Fun(module1Var)); //prints: VALUE and VALUE                
        });
    }
})();
  

是否真的有必要避免with甚至在转发器/加载器中?

我将非常感谢您对这些人的看法,因为我正在考虑编写另一个ES6to5转换器和模块加载器。 :)

2 个答案:

答案 0 :(得分:2)

所以有一些很好的理由不这样做......

......首先,简单来说,JS的不良做法是将全球或全球的工作环境付诸实践。变量,不知道那些变量是什么。

如果该导入的内容发生变化,并且我使用的是with(这不是真正有效的ES5 ...... ...... ES5是严格模式子集,{{1留下来允许ES3代码在ES5浏览器中运行而不会爆炸),然后我要担心的不仅仅是尝试调用已更改的模块上的方法......

with

看起来很好,当然。没有任何伤害。

如果// some-module/v1.0/some-module.js // ... export { doA, doB, a, b } // my-app/index.js import * with "./some-module/v1.0/some-module"; const c = 1; let doC = ( ) => doA( a ) + doB( b ); 是NPM包,并且我处于开发模式,那么我希望在功能添加中不断更新some-module,因为我知道某些功能会使当他们降落时,我的生活更轻松:

some-module

<强> BOOM!

// some-module/v1.5/some-module.js export { doA, doB, doC, a, b, c }; // my-app/index.js import * with "./some-module/v1.5/some-module"; const c = 1; /* ... */ let doC = ( ) => doA( a ) + doB( b );

如果您搜索所有已编译的导入库/模块/组件(假设您的应用程序的入口点中有8个)... ...并且您终于找到了源代码导入c is already defined作为全局,并更新所有您的代码,将c的名称替换为其他名称,然后替换所有对它的引用,以便他们不再爆炸,接下来会发生什么?

<强> BOOM! c

重复此过程并找到有问题的文件。

我们如何解决这些问题?
通常,这是通过命名空间。

我们已经在那些doC is already defined语句中拥有命名空间,这些语句大部分工作正常(在ES7中进一步简化了进一步的提案)。

import

突然之间,您可以清楚地看到应用程序中的任何地方都存在 no 对方法/值冲突的恐惧,除非它是您自己的错误。

此外,如果您加载整个库并决定通过直接引用这些值/方法的某些来节省时间,则可以选择来执行此操作。< / p>

import someModule from "./some-module/v1.0/some-module";

let doC = ( ) => someModule.doA( someModule.a ) + someModule.doB( someModule.b );

仍有0%的歧义,但所有代码都保持尽可能小,这要归功于让消费者选择如何处理导入。

答案 1 :(得分:0)

@norguard, good catch on "strict mode" and module updates, but:

strict mode still can be used in actual execution callback

booms ! definitions of local execution scope will override(hide) definitions of with scope in current context, so there are no problem of redefinition.

// some-module/v1.5/some-module.js
export { doA, doB, doC, a, b, c };
// my-app/index.js
import * with "./some-module/v1.5/some-module";
const c = 1;
/*
  ...
*/
let doC = ( ) => doA( a ) + doB( b );

// translated to:
(function(){
    // with scope contain { doA, doB, doC, a, b, c }
    with (define_module('my-app/index.js',{
        'some-module/v1.5/some-module.js':'*'
    })) {
        execute_module(function(){
            "use struct"

            // local var 'c' overrides definition 'c' of 'with scope'
            // in current function context.
            var c = 1; 
            //  same for 'doC' function 
            var doC = function( ){return doA( a ) + doB( b )};

        });
    }
})();

So the everything above still will work.