Javascript JS扩展方法的功能

Javascript JS扩展方法的功能,javascript,Javascript,我试图扩展2dcontext对象的一些方法的功能,但是我无法让它按我想要的方式工作:我想重写一个方法,但我想从重写的方法调用原始方法,如下所示: //First get the original context var ctx = canvas.getContext("2d"); //Create a class which uses ctx as it's prototype var ExtendedContext = function (){}; ExtendedContext.proto

我试图扩展2dcontext对象的一些方法的功能,但是我无法让它按我想要的方式工作:我想重写一个方法,但我想从重写的方法调用原始方法,如下所示:

//First get the original context
var ctx = canvas.getContext("2d");

//Create a class which uses ctx as it's prototype
var ExtendedContext = function (){};
ExtendedContext.prototype = ctx;

//And extend a method
ExtendedContext.prototype.fillRect = function(x, y, width, height) {
    //Do some stuff
    this.prototype.fillRect(x, y, width, height); //Doesn't work
    //Do some more stuff
};

如何从我自己的方法中调用原始的
fillRect
方法?

您可以像这样存储原始函数的引用:

var oldFillRect = ctx.fillRect;
然后像这样称呼它

ExtendedContext.prototype.fillRect = function() {
    //Do some stuff
    oldFillRect.apply(this, arguments);
    //Do some more stuff
};
这种技术有时被称为“鸭子出击”或“功能挂钩”。在这个特定实例中,您还应该能够使用
Object.getPrototypeOf
方法来获取原始函数引用。这看起来像

ExtendedContext.prototype.fillRect = function() {
    //Do some stuff
    Object.getPrototypeOf(ExtendedContext.prototype).fillRect.apply(this, arguments);
    //Do some more stuff
};

因此,您甚至不需要存储引用。

无需将旧名称保存在单独的对象中,请使用闭包:

ExtendedContext.prototype.fillRect = (function () {
  var oldf = ExtendedContext.prototype.fillRect;
  return function () {
    //Do some stuff
    oldf.apply (this, arguments);
    //Do some more stuff
  };
}) ();
如果你有很多事情要做,这可能会有所帮助:

function extend (fnc) {
  var mthd = (fnc.toString ().match (/^function\s+(\w+)\s*\(/) || ['', ''])[1];

  if (mthd in ExtendedContext.prototype)
    throw ('ExtendContext method ' + mthd + 'does not exist');  

  ExtendedContext.prototype['_' + mthd] = ExtendedContext.prototype[mthd];
  ExtendedContext.prototype[mthd] = fnc;
}
然后您可以按如下方式调用extend

extend (function fillrect () {    
  // Do some stuff
  this._fillrect.apply (this, arguments);
  // Do some more stuff
});

要引用旧方法,请使用其名称前缀“u”

,我迟到了几个月,但我使用了一个相当简单的设计来实现此功能。我们的JavaScript结构使用全局对象来保护代码不受全局变量的影响

对于每个页面/用户控件,我们都在修改全局对象以容纳一个新对象,但是有些代码在不同的地方需要不同的功能,需要扩展方法。我们不希望复制代码并为扩展实例重新定义整个对象,也不希望代码关心如何扩展它

为什么不创建一个通用的扩展方法,而不是在鸭子做你想做的事情之前一直打它呢?根据我们的案例,以下是一个示例:

// Using a Global JavaScript object:
GlobalNameSpace.ExtensionFunction = function(oParam1, oParam2, oParam3)
{
   /// <summary>All parameters are optional</summary>

   return; // For instances when it is not being overwritten, simply return
}

//In the Code to be extended:
GlobalNameSpace.Control.ControlFunction(oSender, oArgs)
{
    ///<summary>Control's function</summary>

    // Function-y stuff..
    GlobalNameSpace.ExtensionFunction(oSender, oArgs);
}

//and finally in the code to extend the functionality
GlobalNameSpace.Page.Init
{
    ///<summary>Initializes the page</summary>

    // redefine the extension function:
    GlobalNameSpace.ExtensionFunction = function(oSender, oArgs)
    {
        // Call the extension function, or just code the extension here
        GlobalNameSpace.Page.Function(oSender, oArgs); 
    }
}
//使用全局JavaScript对象:
GlobalNameSpace.ExtensionFunction=函数(oParam1、oParam2、oParam3)
{
///所有参数都是可选的
return;//对于未被覆盖的实例,只需返回
}
//在要扩展的代码中:
GlobalNameSpace.Control.ControlFunction(oSender、oArgs)
{
///控件的功能
//功能性的东西。。
ExtensionFunction(oSender、oArgs);
}
//最后在代码中扩展功能
GlobalNameSpace.Page.Init
{
///初始化页面
//重新定义扩展函数:
GlobalNameSpace.ExtensionFunction=函数(oSender、oArgs)
{
//调用扩展函数,或者在这里编写扩展代码
GlobalNameSpace.Page.Function(oSender、oArgs);
}
}

这种方法的缺点是,如果您希望一次对多个对象执行此操作,此时最好将扩展方法移动到您特别想要扩展的代码中。这样做将减少扩展代码的通用性,但这可以根据您的需要来决定

我忘了提到,但是我需要重写更多的方法,所以如果可能的话,我不想手动保存我重写的每个函数。但我想我可以简单地循环所有函数,并将它们复制到某个对象。编辑:成功了!谢谢@Tiddo:查看更新
Object.getPrototypeOf
应该可以帮你。我很快回应了:你的最后一个例子似乎不起作用:Object.getPrototypeOf(this).fillRect似乎引用了ExtendedContext.prototype.fillRect,所以它将进入一个无限循环。ExtendedContext.prototype.fillRect重写ctx.fillRect方法,因为原型指向ctx对象。@Tiddo:你说得对。您需要显式地获取
ExtendedContext.prototype
的原型。在那里使用可能有点笨拙。多亏了你上次的建议,我在imo中找到了一个更干净的解决方案:不是每次调用
Object.getPrototypeOf(…)
,而是可以将
Object.getPrototypeOf(ExtendedContext.prototype)
的值添加到
ExtendedContext
的原型中,例如,对于<代码>扩展上下文。原型.PAR ,这样我就可以在自己的函数中简单地使用<代码> .PAR。FILRECT < /代码>。这也是一个非常好的解决方案!