我正在尝试使用Harmony Proxies(Node.js)获取用JavaScript编写的动态服务定位器。基本上你会创建一个新的容器:
var container = new Container();
然后,您就可以像传统服务定位器一样设置和获取值:
container.set('FM', {});
container.get('FM');
container.get('FM', function(FM) {
});
您甚至可以拥有与子对象相似的名称空间:
container.set('FM.Object', {});
问题在于动态别名。
var App = container.alias('App');
创建别名时,它会创建一个新的代理对象,您可以像传统对象一样对其进行操作,但它是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?
现在,我已经组建了一个处理这两个选项的约定。您将使用单数名称来检索值,并使用复数来返回代理。这只是一个快速的“黑客”,因为它不是很有效。
(如果您需要澄清或更多信息,请告诉我)
答案 0 :(得分:3)
让我看看我是否理解正确。听起来您希望“一起”访问的属性被视为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.Zap
和var Bar = App.Foo.Bar; Bar.Zap
。语言中没有任何内容可以区分“一起”访问的属性(var Bar = App.Foo.Bar
)和“单独”访问的属性(Bar.Zap
)。
但是,您可以通过修改语法来接近。我想到了几种不同的可能性,这是我能想到的最好的:
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
);
我确信你知道Proxies是实验性的,但我只想强调ES6的这个特殊功能仍然很不稳定。可能是当前的直接代理提案最终被包含在语言中,但ES中的代理也很可能在明年发生重大变化。 (在过去的一个月中,关于代理提案的ECMAScript邮件列表已经进行了激烈的讨论。)至少对于Node,如果代理发生显着变化(当你更新旧的实现时),你可以继续使用旧版本的Node。
希望这有帮助!