用于构造代理对象的JavaScript模式,使用经典继承
JavaScript pattern for constructing proxy objects, using classical inheritance
虽然没有最终确定,但我正在试验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
。这似乎很痛苦,而且容易出错。使用代理抽象涉及到大量的连接,这对我来说似乎不太正确。
虽然我喜欢代理概念,但我关心的是它的实用性。也许我错过了一些实现目标的更好的练习?
编辑:这个例子过于简化了,因此无法描述我为什么需要它。
最终,我使用代理的目标是允许多重继承。我希望能够混合多个行为(模块)到一个给定的代理对象。我也希望它能很简单地分解行为的心血来潮。通过使用代理,我可以让代理对象管理对方法的访问,并根据需要将信息传递给mixins。基本上,这允许改进面向方面的编程。对于方面,我通常会包装和替换函数。有时,一个给定的方法被几个方面包装和重新包装。AOP的问题在于,一旦以这种方式修改了对象,就不容易删除单个方面,因为该方面可能已经被重新包装所掩盖。
代理没有这个问题。你的mixins可以放在一个数组中。代理处理对这些mixins中找到的方法的调度(甚至是多个方法,因此是多重继承)。那么反混合行为就像从数组中删除mixin一样简单。
代理的问题在于,虽然方法返回对对象本身的引用(用于链接目的)是一种常见的做法,但您实际上不希望任何原始方法返回对该对象的引用(从而绕过代理),而是希望返回代理。
您使用代理创建mixins的目标不是一个坏主意(请参阅这篇博客文章)。然而,你指出的问题,我认为这是你的主要问题,实际上根本不是问题。下面的代码例如:
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的真正好的用例并不多。
但是如果您只想创建像$。代理可以做到,但不想使用jQuery,你可以这样做:
var context = this;
something.addSomeListener( function(){ context.myListener.apply( context, arguments ); } );
- 从控制器继承了隔离的作用域以生成可重用的指令
- 两个指令创建新的继承的和隔离的作用域-元素得到哪个
- Jquery Modal表单登录与AJAX-ASP经典上的IE 9
- 在页面之间传递值的经典ASP
- 当使用控制器作为语法时,如何从父指令继承属性
- 理解经典继承和原型继承之间的区别
- 在 Javascript 中从经典继承切换到原型继承:模式的改变
- Crockford 伪经典继承部分中的函数构造函数
- 使用经典继承,在 JavaScript 中使用“类级”/成员变量是一个好主意还是坏主意
- 是否需要在经典继承中更改子类的“原型.构造函数”
- 了解 Javascript 中的经典继承
- 经典继承和原型继承的区别
- 通过伪经典实例化(JavaScript)掌握原型继承
- 对经典和原型继承Javascript的混淆
- 良好的伪经典JavaScript继承模式
- javascript中的经典继承实现
- 用于构造代理对象的JavaScript模式,使用经典继承
- 经典继承和对象池
- 在crockford的伪经典继承示例中,关于何时使用原型的困惑
- JavaScript中的经典继承:重新分配构造函数