3

我正在尝试使用 Harmony Proxies (Node.js) 用 Ja​​vaScript 编写动态服务定位器。基本上你会创建一个新容器:

 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?

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

(如果您需要澄清或更多信息,请告诉我)

4

1 回答 1

5

问题概述

让我看看我是否理解正确。听起来您希望将“一起”访问的属性视为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)。


提议

但是,您可以通过修改语法来接近。我考虑了几种不同的可能性,这是我能想到的最好的:

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 邮件列表上就代理提案进行了激烈的讨论。)至少对于 Node,如果代理发生巨大变化(当您致力于更新旧实现时),您可以继续使用旧版本的 Node。

希望这可以帮助!

于 2013-01-23T15:15:00.327 回答