dynamic服务定位器在JavaScript中?

我正在尝试使用Harmony代理(Node.js)获得用JavaScript编写的dynamic服务定位器。 基本上你会创build一个新的容器:

var container = new Container(); 

然后,您就可以像传统的服务定位器一样设置和获取值:

  container.set('FM', {}); container.get('FM'); container.get('FM', function(FM) { }); 

你甚至可以拥有像子对象一样的命名空间:

  container.set('FM.Object', {}); 

问题在于dynamic别名。

  var App = container.alias('App'); 

创build别名时,会创build一个新的代理对象,您可以像传统对象那样操作它,但它是get()set()方法的别名。

代替:

  container.get('App.Hello'); 

有了别名,你可以使用:

  App.Hello 

问题在于深名称空间。 假设你试图访问App.Hello.World.Controller ,因为它一次通过代理一个命名空间,而不是一次全部(像那个完整的命名空间)。 如何知道用户是否正在调用App.Hello来检索存储在服务定位器中的值,或者如果用户想要继续访问更深的命名空间? 你不能(从我试过的)。

你还能用其他方法来完成这个吗?

具有语法App.Hello.World ,它将返回一个代理,如果它将访问一个更深的命名空间,或者存储在服务定位器中的值。

  var App = container.alias('App'); App.Controller.Home.Method.Index // It would go through: App -> Proxy App.Controller -> Proxy or Value? App.Controller.Home -> Proxy or Value? App.Controller.Home.Method -> Proxy or Value? App.Controller.Home.Method.Index -> Proxy or Value? 

现在,我已经制定了一个处理这两个选项的公约。 您将使用单数名称来检索值和复数来返回代理。 这只是一个很快的“黑客”,因为它不是很有效。

(如果您需要澄清或更多的信息只是让我知道)

问题概述

让我看看我是否正确理解你。 这听起来像你想要一起访问的属性被认为是controller.get的单个键的一部分。 以下面的例子:

 controller.set('App.Foo.Bar', { Zap: 1 }); controller.set('App.Foo.Bar.Zap', 2); var App = controller.alias('App'); var Bar = App.Foo.Bar; var Zap = Bar.Zap; var Zap2 = App.Foo.Bar.Zap; console.log(Zap, Zap2); // should log: 1, 2 

如果上述行为是你想要的,那么这是不可能的(用这种语法)。 JavaScript只是不区分App.Foo.Bar.Zapvar Bar = App.Foo.Bar; Bar.Zap var Bar = App.Foo.Bar; Bar.Zap 。 语言中没有任何东西可以区分“一起”访问的属性( var Bar = App.Foo.Bar )和“分开”访问的Bar.ZapBar.Zap )。


提案

但是,您可以通过修改语法来closures它。 我想了几个不同的可能性,这是我能想到的最好的:

 controller.set('App.Foo.Bar', { Zap: 1 }); controller.set('App.Foo.Bar.Zap', 2); var App = controller.alias('App'); // Use parens to note that we are ending the key name // and want it to retrieve a value. var Bar = App.Foo.Bar(); var Zap = Bar.Zap; var Zap2 = App.Foo.Bar.Zap(); console.log(Zap, Zap2); // should log: 1, 2 

如果在属性检索之后添加括号,如上所述,那么您可以使用此语法作为代理的区别笔记,这意味着要从控制器中检索值。


履行

这是可能的代码:

 var Container = (function() { return function Container() { var map = { }; this.get = function get(key) { return map[key]; }; this.set = function set(key, value) { map[key] = value; }; this.alias = function alias(name) { return createAlias(this, name); }; }; function createAlias(container, aliasName) { return new Proxy( function() { return container.get(aliasName); }, { get: function(target, name) { return createAlias(container, aliasName + '.' + name); }, set: function(target, name, value) { container.set(aliasName + '.' + name, value); } } ); } })(); 

你可以用=来设置,用()检索:

 var container = new Container(); container.set('App.Controller.Home.Method.Index', 5); var App = container.alias('App'); App.Controller.Home.Method = 7; console.log( App.Controller.Home.Method(), // => 7 App.Controller.Home.Method.Index() // => 5 ); 

最后的注意

我确定你知道代理是实验性的,但我只想强调,ES6的这个特性还是相当不稳定的。 现在的直接代理提案可能会被包含在语言中,但ES代理也很有可能在明年发生重大变化。 (在过去一个月中,关于代理提案的ECMAScript邮件列表已经进行了激烈的讨论。)至less在Node中,如果代理发生巨大变化(当您正在更新旧的实现时),您可以继续使用旧版本的Node。

希望这可以帮助!