如何重用和覆盖继承的javascript函数

| 我有一个有关鼠标事件的类。我正在使用dojo b / c,我喜欢它的面向对象方法
dojo.declare(\"MouseObject\", null, {
  constructor: function(){},
  onclick : function(){...},
  _onClick : function(){...}
});
_onClick()
监听窗口生成的鼠标按下/释放事件,并确定是否发生单击。如果有,将调用
onClick()
onClick()
执行所有可能的点击共有的功能,因此每次用户单击时都需要调用它。 有时用户可能想扩展ѭ2的功能,是否仍然可以合并原始功能而不进行复制粘贴?我可以想到两种方法,我都不喜欢
dojo.declare(\"MouseObjectChild\", [MouseObject], {
  constructor: function(){},
  onclick : function(){this.inherited(arguments);...}
});
这样做的缺点是我必须继续创建我真正不需要的新类,并添加两个中间函数
dojo.declare(\"MouseObject\", null, {
      constructor: function(){},
      onclick : function(){this._onClick()...}, //child onClick
      _onClick : function(){...}, //parent onClick
      __onClick : function(){...} //listener
    });
但这看起来不像是好的代码 赏金大方,我希望获得有关如何最好地解决程序与用户交互问题的专家意见。如果程序提供了至关重要的功能,例如在画布上画一个圆圈,那么用户将如何与之交互。如果用户想在圆后方画一个三角形怎么办?圆圈前有一个正方形?然后,该程序将必须提供像这样的前置和后置方法:
beforeDraw();
draw();
afterDraw();
这被认为是好的设计吗?我应该将函数指针放在数组中并按顺序调用它们吗?     
已邀请:
        正如“我应该将函数放在它们自己的数组中并按顺序调用它们”和“构建自己的事件系统”这样的想法所建议的那样,您可能想看看附带的dojox.lang.aspect库。捆绑在扩展标准库中。它基本上应该是“ dojo.connect \”解决方案的更高级版本。
dojo.require(\'dojox.lang.aspect\');
var aop = dojox.lang.aspect;

function log(msg){ return function(){
    console.log(msg);
};}

var obj = {
   draw : log(\'draw circle\');
};

obj.foo();
//prints
//  draw circle

aop.advise(obj, \'draw\', [
    {before: log(\'draw triangle\')},
    {after: log(\'draw a square\')},
    {after: log(\'done!\')}
]);

obj.foo();
//prints
//  draw a triangle
//  draw a circle
//  draw a square
//  done!
    
        如果有人只想在调用onclick()时运行一些代码,则可以连接到该代码。请注意,不仅可以使用dojo.connect()事件连接到函数调用。
dojo.connect(obj, \'onclick\', function(){
  // Some extra code that runs when obj.onclick() is called
});
如果他想创建一个新类并扩展该功能,则调用
this.inherited(arguments);
是最好的方法。     
        为什么不创建自己的简单事件模型?
// store our callbacks
var hooks = {};

// add a callback
var hook = function(name,fn){
  if(typeof hooks[name] === \'undefined\'){
    hooks[name] = [];
  }
  hooks[name].push(fn);
  return true;
};

// remove a callback
var unhook = function(name,fn){
  if(typeof hooks[name] === \'undefined\'){ return false }
  var i, u = hooks[name].length;
  for(i=0;i<u;i++){
    if(hooks[name][i] === fn){
      hooks[name].splice(i,1);
      return true;
    }
  }
};

// trigger a callback
var callHook = function(name, data){
   if(typeof hooks[name] === \'undefined\'){ return false }
   var i, u = hooks[name].length;
   for(i=0;i<u;i++){
     hooks[name][i](data);
   }
};
然后稍后(示例通过上下文):
hook(\'beforeDraw\',function(ctx){ 
  console.log(\'I am called prior to drawing\');
});

hook(\'afterDraw\',function(ctx){
  console.log(\'I am called after drawing\');
});

var drawCircle = function(){
  callHook(\'beforeDraw\', ctx);
  // drawing code here
  callHook(\'afterDraw\', ctx);
};
或者,如果您想将范围传递给回调,则可以将
callHook
方法更改为接受范围参数,然后使用
call
apply
并传入
this
或其他对象:
var callHook = function(name, scope, data){
   if(typeof hooks[name] === \'undefined\'){ return false }
   var i, u = hooks[name].length;
   for(i=0;i<u;i++){
     hooks[name][i].call(scope, data);
   }
};

// later
var drawCircle = function(){
   callHook(\'beforeDraw\', this, ctx);
   // or
   callHook(\'beforeDraw\', someObject, ctx);
};
根据定义事件模型函数的方式和位置,可以将功能范围限定于对象的特定实例,对象的每个实例,全局范围,等等,取决于要如何分配,更改和触发这些回调。     
        您有几种选择。 1. Promise模式越来越流行(尽管有竞争规范):http://wiki.commonjs.org/wiki/Promises/B。 jQuery的实现接近于B,并且有据可查。它具有最多的选择,功能强大,但起初不容易将头缠起来。 AOP风格的编程使您可以摆弄之前和之后的建议。但是,要使其正常工作,您需要停止将所有内容放入匿名函数中,并在实例化之后应用建议还是通过将功能烘焙到类中来决定使用建议。这需要更多的代码结构计划,但提供了大量实用程序。 例如:
var MYAPP = {
  onClick: function () {
    //do something...
  }
};

dojo.declare(\"MouseObject\", null, {
  constructor: function(){},
  onclick : function(){...},
  _onClick : function(){
    return MYAPP.onClick.apply(this, arguments);
  }
});
由于我的班级每次都调用MYAPP(是的,因此要收取一定的范围费用),因此我可以操纵挂在MYAPP上的函数,使用它的任何人都会受益。
MYAPP.after(\"onClick\", function () {...}); //lots of ways to write .after, just google some AOP js or use a library
另一边:
var MYAPP = {
  onClick: function () {
    //do something...
  }
};

dojo.declare(\"MouseObject\", null, {
  constructor: function(){},
  onclick : function(){...},
  _onClick : MYAPP.onClick
});
现在,我无法更改MYAPP并查看MouseObject或其实例中的更改,因为该函数已通过引用传递给MouseObject。我只能使用AOP更改实例(或通过更改类的原型来更改所有将来的实例)。 就像是:
var m = new MouseObject();
m.after(\"onClick\", function () {...}); //you need to add .after to your class or use an apply pattern from library code
它仅取决于您如何使用它:某些实例,将来的所有实例(直到关闭)或所有其他内容。 建议使用“事件队列”。这更像是活动对象模式,其中您使用对象数组和队列管理器来管理任务。这是最容易实现的方法,但是有几个缺点,即队列可能被“阻塞”并且不再进行处理。我基于我编写的iPhone应用程序为这种管理类型写了一个库,称为proto-q(http://code.google.com/p/proto-q/)。它对我来说效果很好,但并不是针对每个人的应用程序。     
__fn变得越来越混乱。我的朋友,那是通向地狱的道路。 这是使用魔术按钮方法的症状。 您应该考虑使用周围的许多OO js库迁移到基于实际继承的类模型。然后,您可以调用$ base.fn()或$ super.fn()     
        如果我理解您的问题,那么您想针对特定情况修改功能。如果是这种情况,并且您不希望有任何开销,那么我将在实例化时依赖重写方法。 替代模型 你的班:
dojo.declare(\"some.path.DrawingThing\", [dijit._Widget], {
    draw: function () {
        this.inherited(arguments); // Call super class methods
        // override this method to do specialized things that\'re specific 
        // to an instance.
    }
});
客户端实例化:
var drawer = new some.path.DrawingThing({
    draw: function () {
        beforeDraw();
        // Access the pre-existing functionality in a somewhat dirty way.
        this.constructor.prototype.draw.apply(this, arguments);
        afterDraw();
    }
});
如果您遵循此模型,则代码会更少,但并不是那么干净。另一个选择是编写一个真实的API,请参见下文。 事件模型 如果您想要一个真正的API,那么我将提供事件:
// Dojo 1.6 style declaration.
dojo.declare(\"some.path.DrawingThing\", [dijit._Widget], {
    onBeforeDraw: function(){
        // Hook into this method to do something before draw
    },
    onDraw: function(){
        // Hook into this method to do something after draw
    },

    draw: function () {
        // This method is actually called when the draw even fires
        this.onBeforeDraw();
        this.inherited(arguments); // Call super class methods
        this.onDraw();
    }
});
    

要回复问题请先登录注册