覆盖并恢复功能

时间:2015-06-30 11:59:41

标签: javascript function

我需要在JavaScript中模拟调用函数。为此,我将函数“保存”在临时变量中,使用新的功能块更新目标,调用目标然后恢复旧函数:

var myObject = {
  myIntProp: 1,
  myFunc: function(value) {
    alert(value + 1);
  }
};
myObject.myFunc(2);

var tmp = myObject.myFunc;
myObject.myFunc = function(value) {
  alert(value - 1);
};
myObject.myFunc(2);

myObject.myFunc = tmp;
myObject.myFunc(2);

这可以正常工作:函数被覆盖然后成功恢复。我的想法是将此代码移动到辅助函数中,并在需要时轻松使用它:

function FunctionSwapper(target, newFunction) {
  var old = target;
  target = newFunction;
  this.Restore = function() {
    target = old;
  }
};

var myObject = {
  myIntProp: 1,
  myFunc: function(value) {
    alert(value + 1);
  }
};
myObject.myFunc(2);

var swapp = new FunctionSwapper(myObject.myFunc, function(value) {
  alert(value - 1);
});
myObject.myFunc(2);

swapp.Restore();
myObject.myFunc(2);

但是,此代码不保存当前状态,也不替换目标函数。我在这里错过了什么?是不是一个函数总是作为参考传递?两个代码片段之间的主要区别是什么?

JSFiddle可用,但准备8 alert s ...)

编辑:一位同事已经指出第二种方法与第一种方法没有什么不同,而且创建额外的类可能不值得。虽然我理解并同意他们的论点,但我认为第二种方法有两个优点(两者都适用于我的特定,现实案例):

  1. 在处理具有多个子元素级别的对象时,swapp.Restore();myNameSpace.level2.level3.level4.level5 = swap;更容易/更快,
  2. 它抽象操作,在开发团队中提供一致的使用(此外,可以在类中进行日志记录或类型校对)。

3 个答案:

答案 0 :(得分:5)

这是因为target不是真正的引用,它是一个引用target函数的值。

但是,当您重新分配目标时,不会修改保留的值(对函数的引用),但是您可以直接修改该值,这意味着您不能这样做。

相反,您可以传递持有要替换的函数的对象(它只能用于对象,因为您需要稍后访问它)。

这是我提出的

function FunctionSwapper(target, name, newFunction) {
  var old = target[name];
  target[name] = newFunction;
  this.Restore = function() {
    target[name] = old;
  }
};

var myObject = {
  myIntProp: 1,
  myFunc: function(value) {
    alert(value + 1);
  }
};
myObject.myFunc(2);

var swapp = new FunctionSwapper(myObject, 'myFunc', function(value) {
  alert(value - 1);
});
myObject.myFunc(2);

swapp.Restore();
myObject.myFunc(2);

答案 1 :(得分:3)

FunctionSwapper正在恢复自己的功能副本,但它与myObject没有任何关联(您不会将其传递给myObject)。

这样可行:

function FunctionSwapper(object,name,newFunction) {
  var old = object[name];
  object[name] = newFunction;
  this.Restore = function() {
    object[name] = old;
  }
};

...

var swapp = new FunctionSwapper(myObject, "myFunc", function(value) {
  alert(value - 1);
});

答案 2 :(得分:3)

我相信通过传递myObject.myFunc,您实际上会从myObject中断参考,因此它实际上并未更新myFunc myObject的{​​{1}}来电,它会更新FunctionSwapper副本的本地范围。

将它与此进行比较,它对对象本身执行操作:

function FunctionSwapper(obj, funcName, newFunction) {
    var old = obj[funcName];
    obj[funcName] = newFunction;
    this.Restore = function() {
        obj[funcName] = old;
    }
};

var myObject = {
  myIntProp: 1,
  myFunc: function(value) {
    alert(value + 1);
  }
};
myObject.myFunc(2);

var swapp = new FunctionSwapper(myObject, "myFunc", function(value) {
  alert(value - 1);
});
myObject.myFunc(2);

swapp.Restore();
myObject.myFunc(2);