0

所有当前的模块加载器都喜欢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 的简单示例翻译,可以解决问题:

文件:模块/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
                // ...
            };
        });
    }
})();

文件:模块/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 翻译器和模块加载器。:)

4

2 回答 2

2

所以有几个很好的理由不这样做......

...首先是在 JS 中使用全局或“全局”变量来涂抹工作上下文是一种不好的做法,而不知道这些变量是什么。

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

// 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 );

看起来不错,当然。一点伤害都没有。

如果some-module是一个 NPM 包,并且我处于开发模式,那么我想some-module在功能添加中不断更新,因为我知道某些功能会在它们登陆时让我的生活更轻松:

// 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 );

繁荣!

c is already defined.

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

繁荣! doC is already defined.

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

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

我们已经在那些运行良好的语句中包含了命名空间import在 ES7 中进一步简化了进一步的建议)。

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

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

突然之间,您可以清楚地看到,在您的应用程序的任何地方都无需担心方法/值冲突,除非这是您自己的错。

此外,如果您加载整个库并决定通过直接引用其中一些值/方法来节省时间,您可以选择这样做。

import someModule from "./some-module/v1.5/some-module";
const { a, b } = someModule;
let { doA, doB } = someModule;

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

仍然存在 0% 的歧义,但由于让消费者可以选择如何处理导入,所有代码都已尽可能小。

于 2015-05-24T19:06:08.147 回答
0

@norguard,很好地了解“严格模式”和模块更新,但是:

严格模式仍然可以在实际执行回调中使用

繁荣!本地执行范围的定义会覆盖(隐藏)当前上下文中 with 范围的定义,所以不存在重新定义的问题。

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

        });
    }
})();

所以上面的一切仍然有效。

于 2015-05-24T21:30:50.050 回答