4

虽然尚未最终确定,但我正在尝试使用 ES6 代理。我的目标是拥有一个构造函数(一个利用如下所示的经典继承的函数)来创建具有继承链的代理对象。

function inherit(child, parent){ //a classical inheritance pattern
  var F = function(){};
  F.prototype = parent.prototype; 
  child.prototype = new F(); 
  child.parent = parent.prototype; 
  child.prototype.constructor = child;
  return child;
}

以下看起来合理吗?我创建一个项目并从构造函数返回代理。任何将返回对实例的引用(出于链接目的)的方法都必须返回对代理的引用,否则在链接时我们会丢失代理。

function Item(attrs){
  this.attrs = attrs;
  var proto = this.constructor.prototype;
  return this.proxy = Proxy.create(new MyHandler(this), proto);
}
Item.prototype.setStatus = function(status){
  //do work
  return this.proxy; //we do this everywhere instead of a simple 'this'?
}
function DVD(attrs){
   attrs.type = 'DVD';
   return Item.call(this, attrs);
}

inherit(DVD, Item);

var negotiator = new DVD({title: 'The Negotiator'}); //returns proxy

目标是构造可能是经典继承链产物的代理对象(通过'new'关键字)。

下一期。考虑一下如果我用 Backbone.Events 扩展我的 Item 原型会发生什么。那些导入的方法将返回this而不是this.proxy. 为了解决这个问题,我必须包装所有返回的导入方法this以便返回proxy。这似乎很痛苦且容易出错。使用 Proxy 抽象涉及大量布线,这对我来说似乎不太正确。

虽然我喜欢代理概念,但我关心它的实用性。也许我错过了一些更好的实践来实现我的目标?

编辑:

这个例子过于简单,因此无法描述我为什么需要它。

最终,我使用代理的目标是允许多重继承。我希望能够将多个行为(模块)混合到给定的代理对象中。我还希望能够简单地随心所欲地分解行为。

通过使用代理,我可以让 Proxy 对象管理对方法的访问,并根据需要将信息传递给 mixins。基本上,这允许改进面向方面的编程。对于一个方面,我通常会包装和替换一个函数。有时,给定的方法会被多个方面包装和重新包装。AOP 的问题在于,一旦您以这种方式修改了一个对象,就很难仅删除一个方面,因为该方面可能已被重新包装所掩埋。

代理不会遇到这个问题。你的 mixin 可以改为放在一个数组中。代理处理对这些 mixin 中的方法的分派(甚至是多个方法,因此是多重继承)。然后,取消混合行为就像从该数组中删除一个 mixin 一样简单。

代理的问题在于,虽然方法返回对对象本身的引用是一种常见做法(出于链接目的),但您并不真正希望任何原始方法返回对该对象的引用(因此绕过代理),您希望返回代理。

4

2 回答 2

1

您使用代理创建 mixin 的目标是一个不错的主意(请参阅此博客文章)。但是,您指出的问题是您的主要问题,实际上根本不是问题。这段代码例如:

var o, p;

function Obj() {  }
Obj.prototype.whoAmI = function() {
    console.log("I am the "+ (this == o ? "object" : "proxy"));    
    return this;
};

o = new Obj(); 
var p = new Proxy(o, {});

o.whoAmI().whoAmI();
p.whoAmI().whoAmI();

将输出:

I am the object
I am the object
I am the proxy
I am the proxy

如您所见,this在目标对象中使用的关键字实际上是代理。因此,如果目标对象返回this,它实际上会返回代理。正是你想要的。

如果您想绝对确定返回代理对象,您可以像这样包装您的代理方法:

var o, p;

function Obj() {  }
Obj.prototype.whoAmI = function() {
    console.log("I am the "+ (this == o ? "object" : "proxy"));    
    return o; // bit of a code smell here
};

o = new Obj(); 
var p = new Proxy(o, {
    get: function(target, name) {
        return function() {
            var rtnVal = target[name].call(this);
            return rtnVal == target ? this : rtnVal;
        }
    }
});

p.whoAmI().whoAmI(); 

这将输出:

I am the proxy
I am the proxy

这确保返回的对象永远不是展开的对象。

这一切当然不是很利于你的方法调用的性能。相反,我会建议对 javascript mixins采用更传统的方法。据我所知,动态打开和关闭 mixins 的用例并不多。

于 2013-05-04T14:17:25.977 回答
0

但是,如果您只想创建像 $.proxy 这样的代理函数,但不想使用 jQuery,您可以这样做:

var context = this;
something.addSomeListener( function(){ context.myListener.apply( context, arguments ); } );
于 2014-01-16T10:44:58.403 回答