2015-05-24 58 views
0

所有当前模块装载机等AMD,CommonJS,SystemJS使用变量定义为加载外部物体进入当前模块范围动态ES6模块作用域

像:

var something = require('something'); 

或:

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

万一当你不知道你需要从外部模块导入什么,或者只需要导入所有东西时,这个becom因为不可能在运行时定义变量。

我想这就是为什么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简单的例子的翻译,可以解决问题:

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

是真的有必要避免甚至在transpilers /装载机with

我会很感激你对这个家伙的想法,因为我正在考虑编写另一个ES6to5翻译器和模块加载器。 :)

+0

为什么你想写一个不符合规格的翻译?这对我来说似乎没有意义。当然,你可以做任何你想做的,并使用自己的JS方言。 –

回答

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

BOOM!

c is already defined

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

BOOM! 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%模棱两可,然而所有的代码一直保持尽可能的小,由于给消费者如何办理进口的选择。

+0

对不起,没有找到一个方法来评论你的答案,所以我已经回答了你的回答评论:) –

+0

加一个使用单词“slather”。 –

0

@norguard,好抓的 “严格模式” 和模块更新,但:

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

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

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

     }); 
    } 
})(); 

所以上面的一切仍然正常工作。

+0

我真的不确定你希望从中得到什么。首先:规范期望从my-module中导入myModule;等同于'var myModule = require(“my-module”)。default;',就像现在这样。该变量在模块的根范围*中定义*,而在模块的根范围内仅定义***(在顶部以外的任何范围使用'import' /'export'语句实际上是无效的而且,就像我刚才提到的那样,如果你有8个文件,那么你就是在用你的“index.js”,每个文件有5-10个IT,通过... – Norguard

+0

...你是如何解决这个问题的吗?它现在是JS规范的一部分,我依赖的模块现在依赖于顺序吗?如果我导入“1.js”,“2.js”和“3.js”,我的全局变量应该与“3.js”“2.js”“1.js”不同,最后是“Temporal Dead Zone”,我不能使用'let'或'const'来定义已经在当前范围内初始化的东西,而且,我不能在引用它的地方引用它的值*,包括阴影,所以假设你符合整个规范,就会失效。没事的......但那是你的特权...... – Norguard